Dyalog User Commands: Difference between revisions

From APL Wiki
Jump to navigation Jump to search
(Link corrected)
 
(4 intermediate revisions by 2 users not shown)
Line 1: Line 1:
== Overview ==
== Overview ==
User commands are useful for the Dyalog  APL developer. Dyalog comes with a rich set of user commands, but independent parties also develop and maintain user commands. This article discusses how and where to install third-party user commands, and how to load them into <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight>.
User commands play a crucial role for Dyalog  APL developers. Dyalog comes with a rich set of user commands, but independent parties also develop and maintain user commands. This article discusses how and where to install third-party user commands, and how to load them into <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight>.


This article assumes that you are familiar with the concept of Dyalog user commands, and that you know what a user command script is, and what specific features and properties it has. If you are not familiar with these topics this article is not for you: study Dyalog's "User Commands User Guide" first.
== Prerequisite Knowledge ==


Dyalog installs its own set of user commands into <syntaxhighlight lang=apl inline>[DYALOG]/SALT/spice</syntaxhighlight>. Installing third-party user commands into this folder has advantages and disadvantages.
This article assumes that you are familiar with the concept of Dyalog user commands, and understand what a user command script is, along with its specific features and properties.
If you are new to these topics, it is recommended to first study Dyalog's [https://www.dyalog.com/documentation_182.htm "User Commands User Guide"].


Pro:
== Installing user commands ==


* The user commands cannot be changed by an ordinary user (admin rights are required for that)
Dyalog installs its own set of user commands into <syntaxhighlight lang=apl inline>[DYALOG]/SALT/spice</syntaxhighlight>. Installing third-party user commands into this folder comes with both advantages and disadvantages.
 
Advantages of installing into the <syntaxhighlight lang=apl inline>[DYALOG]/SALT/spice</syntaxhighlight> folder:
 
* User commands cannot be modified by ordinary users; admin rights are required
* Every version of Dyalog has its own set of user commands
* Every version of Dyalog has its own set of user commands


But what some may consider an advantage can also be viewed as a disadvantage. Installing it into a different place, the folder <syntaxhighlight lang=apl inline>MyUCMDs/</syntaxhighlight> (we discuss in a second where that folder lives), has some advantages:
On the other hand, installing user commands in a different folder, such as <syntaxhighlight lang=apl inline>MyUCMDs/</syntaxhighlight>, has its own advantages:


* The user has "write" permission to that folder, so updating is easy
* Users have write permission to this folder, making updates easier
* Anything installed into this folder will be available in all installed versions of Dyalog APL
* Anything installed into this folder will be available in all installed versions of Dyalog APL
* Each user has their own <syntaxhighlight lang=apl inline>MyUCMDs/</syntaxhighlight> folder, which can be seen as an advantage or disadvantage based on individual preferences


Note that every user has their own folder <syntaxhighlight lang=apl inline>MyUCMDs/</syntaxhighlight>. Again this might be considered an advantage or a disadvantage.


Like the <syntaxhighlight lang=apl inline>SALT/spice</syntaxhighlight> folder, <syntaxhighlight lang=apl inline>MyUCMDs/</syntaxhighlight> is scanned for user command scripts at startup time.
Both the <syntaxhighlight lang=apl inline>SALT/spice</syntaxhighlight> folder and the <syntaxhighlight lang=apl inline>MyUCMDs/</syntaxhighlight> folder are scanned for user command scripts at startup.


== Where does the folder MyUCMDs/ live? ==
== Location of the MyUCMDs/ folder ==


The answer to this question depends on the operating system used.
The location of the MyUCMDs/ folder depends on the operating system used:


* Under Windows it's usually <syntaxhighlight lang=apl inline>C:\Users\<username>\Documents\</syntaxhighlight>
* On Windows it's usually <syntaxhighlight lang=apl inline>C:\Users\<username>\Documents\</syntaxhighlight>
* Under Linux and Mac OS it is <syntaxhighlight lang=apl inline>/home/<username>/</syntaxhighlight>
* On Linux it is <syntaxhighlight lang=apl inline>/home/<username>/</syntaxhighlight>
* On Mac OS it is <syntaxhighlight lang=apl inline>/Users/<username>/</syntaxhighlight>


Note that this folder is created by the Dyalog APL installer under Windows but it won't exist under Linux and Mac OS in versions before 19.0, so you need to create the folder yourself on non-Windows platforms.
Note that <syntaxhighlight lang=apl inline>MyUCMDs/</syntaxhighlight>  is created by the Dyalog APL installer on Windows, but you need to manually create it on non-Windows platforms before version 19.0.


If you have Tatin installed, or you are using version 19.0 or later (those come with Tatin automatically) then you can call this Tatin API function:
If you have [https://github.com/aplteam/Tatin Tatin] installed, or you are using version 19.0 or later (those come with Tatin) then you can call this Tatin API function:


<syntaxhighlight lang=apl>
<syntaxhighlight lang=apl>
       ⎕se.Tatin.GetMyUCMDsFolder'foo'
       ⎕se.Tatin.GetMyUCMDsFolder'' ⍝ Windows
C:\Users\kai\Documents\MyUCMDs
C:\Users\<username>\Documents\MyUCMDs
</syntaxhighlight>
</syntaxhighlight>


== Availability of user commands ==
== Availability of user commands ==


Once a user command script is moved into a <syntaxhighlight lang=apl inline>MyUCMDs/</syntaxhighlight> folder (or a sub-folder of it) the user command will be available from any version of APL.
Once a user command script is moved into the <syntaxhighlight lang=apl inline>MyUCMDs/</syntaxhighlight> folder (or a sub-folder of it), the user command becomes available across all versions of APL.


And that could be the end of the story in case the user command you want to install is relatively simple, so all the code can go into the script.
For simple user commands where all the code resides in the script itself, this is the end of the process. However, if a user command relies on a larger set of code files that need to be loaded into <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight> for execution, additional steps are required.
It's a different story when the user command relies on, say, a large set of code files that need to be loaded into <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight> in order to execute the user command.  


Now of course the user command script could check whether the code is already available in <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight> and if not do the loading, and that would work just fine.
The user command script could of course check whether the code is already available in <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight> and if not load it, and that would work just fine.


== User commands with an API ==
== User commands with an API ==


However, these days it is becoming increasingly popular to add an API to a user command.
It has become increasingly popular to add an API to user commands. For example, the Dyalog APL project manager Cider offers a rich set of user commands:
 
For example, the Dyalog APL project manager [https://github.com/aplteam/Cider Cider] comes with a rich set of user commands:


<syntaxhighlight lang=apl>
<syntaxhighlight lang=apl>
Line 68: Line 71:
</syntaxhighlight>
</syntaxhighlight>


But Cider also offers a public interface:
But Cider also offers an API (public interface):


<syntaxhighlight lang=apl>
<syntaxhighlight lang=apl>
Line 91: Line 94:
</syntaxhighlight>
</syntaxhighlight>


If you want to use any of these API functions without the need of first calling any of the Cider user commands (that would allow the user command script to load the code into <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight>), then you have to make sure that the code is loaded, ideally at a very early stage: as part of the instantiating process.
If you want to use any of the API functions without the need of first calling one of the Cider user commands (that would force the user command loading the code into <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight>), then you have to make sure that the code is loaded by other means, ideally at an early stage: as part of the bootstrapping process.


This brings us to the real topic of this article: how to achieve that!


== setup.dyalog in MyUCMDs/ ==
== Introducing setup.dyalog in MyUCMDs/ ==


We are going to introduce a script <syntaxhighlight lang=apl inline>setup.dyalog</syntaxhighlight> into the folder <syntaxhighlight lang=apl inline>MyUCMDs/</syntaxhighlight>. We are doing this because when Dyalog finds such a script then it will check whether it has a function <syntaxhighlight lang=apl inline>Setup</syntaxhighlight>. If so then this function will be executed.
To address this, a script named <syntaxhighlight lang=apl inline>setup.dyalog</syntaxhighlight> is introduced in the <syntaxhighlight lang=apl inline>MyUCMDs/</syntaxhighlight> folder. When Dyalog encounters this script, it checks for the presence of a function called <syntaxhighlight lang=apl inline>Setup</syntaxhighlight> and executes it.


Notes:
Notes:


* The name of the script must be lowercase because otherwise it won't be found on non-Windows platforms
* The script name must be lowercase to ensure compatibility with non-Windows platforms
* The script can be a class or a namespace
* The script can be a class or a namespace
* The function <syntaxhighlight lang=apl inline>Setup</syntaxhighlight> must accept a right argument
* The <syntaxhighlight lang=apl inline>Setup</syntaxhighlight> function must accept a right argument


  In our case, the right argument will be an <syntaxhighlight lang=apl inline>i</syntaxhighlight> which stands for <syntaxhighlight lang=apl inline>init</syntaxhighlight>
* The function <syntaxhighlight lang=apl inline>Setup</syntaxhighlight> must return a result
* The function <syntaxhighlight lang=apl inline>Setup</syntaxhighlight> must return a result
  The result will be ignored by the caller


=== There is no setup.dyalog yet ===
=== There is no setup.dyalog yet ===
Line 159: Line 159:
</syntaxhighlight>
</syntaxhighlight>


Note that this also checks the version of Dyalog APL and whether it's "Classic" or not. Amend this to your needs.
Note that this also checks the version of Dyalog APL and whether it's "Classic" or not. Please customize the script to fit your specific needs. Ensure to modify the <syntaxhighlight lang=apl inline>IfAtLeastVersion</syntaxhighlight> function, if necessary.


If your user command is not a Tatin package then this will do.
If your user command is not a Tatin package then this will do.
Line 165: Line 165:
=== There is already a setup.dyalog ===
=== There is already a setup.dyalog ===


Copy the functions <syntaxhighlight lang=apl inline>IfAtLeastVersion</syntaxhighlight>, <syntaxhighlight lang=apl inline>GetMyUCMDsFolder</syntaxhighlight> and </syntaxhighlight>LoadMyUserCommand</syntaxhighlight> from above into your own <syntaxhighlight lang=apl inline>setup.dyalog</syntaxhighlight> script and then make sure that <syntaxhighlight lang=apl inline>LoadMyUserCommand</syntaxhighlight> is called from your </syntaxhighlight>Setup</syntaxhighlight> function.
Copy the functions <syntaxhighlight lang=apl inline>IfAtLeastVersion</syntaxhighlight>, <syntaxhighlight lang=apl inline>GetMyUCMDsFolder</syntaxhighlight> and <syntaxhighlight lang=apl inline>LoadMyUserCommand</syntaxhighlight> from above into your own <syntaxhighlight lang=apl inline>setup.dyalog</syntaxhighlight> script.
 
Make sure that <syntaxhighlight lang=apl inline>LoadMyUserCommand</syntaxhighlight> is called from your <syntaxhighlight lang=apl inline>Setup</syntaxhighlight> function.


This makes sure that the API of your user command is available right after instantiating Dyalog APL.
This makes sure that the API of your user command is available right after instantiating Dyalog APL.
Line 188: Line 190:
Notes:
Notes:


* There is no name specified after <syntaxhighlight lang=apl inline>[MyUCMDs]</syntaxhighlight> in the second argument of <syntaxhighlight lang=apl inline>InstallPackages</syntaxhighlight>: this makes the function act on the name of the package, here <syntaxhighlight lang=apl inline>MyUserCommand</syntaxhighlight>
* There is no name specified after <syntaxhighlight lang=apl inline>[MyUCMDs]</syntaxhighlight> in the second argument of <syntaxhighlight lang=apl inline>InstallPackages</syntaxhighlight>: this makes the function use the name of the package for the folder to be created in <syntaxhighlight lang=apl inline>MyUCMDs/</syntaxhighlight>, here <syntaxhighlight lang=apl inline>MyUserCommand</syntaxhighlight>
 
* <syntaxhighlight lang=apl inline>LoadDependencies</syntaxhighlight> will look for a folder <syntaxhighlight lang=apl inline>MyUserCommand</syntaxhighlight> in the <syntaxhighlight lang=apl inline>MyUCMDs/</syntaxhighlight> folder. If there is one, and it contains a file <syntaxhighlight lang=apl inline>apl-dependencies.txt</syntaxhighlight>, then the package will be loaded into <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight>.
* <syntaxhighlight lang=apl inline>LoadDependencies</syntaxhighlight> will look for a folder <syntaxhighlight lang=apl inline>MyUserCommand</syntaxhighlight> in the <syntaxhighlight lang=apl inline>MyUCMDs/</syntaxhighlight> folder. If there is one, and it contains a file <syntaxhighlight lang=apl inline>apl-dependencies.txt</syntaxhighlight>, then the package will be loaded into <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight>.
* Usually <syntaxhighlight lang=apl inline>LoadDependencies</syntaxhighlight> loads packages into <syntaxhighlight lang=apl inline>#</syntaxhighlight> in case no second argument is specified, but because the folder was specified as an alias (<syntaxhighlight lang=apl inline>[MyUCMDs]</syntaxhighlight>) the function knows that this is about a user command, and therefore the default target for the load operation is <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight> and not <syntaxhighlight lang=apl inline>#</syntaxhighlight>.
 
* The user command script <syntaxhighlight lang=apl inline>MyUserCommand.dyalog</syntaxhighlight> is moved to the top of the folder hosting the user command, here <syntaxhighlight lang=apl inline>[MyUCMDs]/MyUserCommand</syntaxhighlight>
* Usually <syntaxhighlight lang=apl inline>LoadDependencies</syntaxhighlight> loads packages into <syntaxhighlight lang=apl inline>#</syntaxhighlight> in case no second argument is specified, but because the folder was specified as an alias (<syntaxhighlight lang=apl inline>[MyUCMDs]</syntaxhighlight>) the function knows that this is about a user command, and therefore the default target for the load operation is <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight> rather than <syntaxhighlight lang=apl inline>#</syntaxhighlight>.
 
* The user command script <syntaxhighlight lang=apl inline>MyUserCommand.dyalog</syntaxhighlight> is moved to the top of the folder hosting the user command by <syntaxhighlight lang=apl inline>]Tatin.Installpackages</syntaxhighlight>, here <syntaxhighlight lang=apl inline>[MyUCMDs]/MyUserCommand</syntaxhighlight>


=== Loading all such user commands ===
=== Loading all such user commands ===


If you want to make sure that all user commands that are Tatin packages are loaded into <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight> at an early stage add this to your <syntaxhighlight lang=apl inline>setup.dyalog</syntaxhighlight> script and make sure that it is called by your <syntaxhighlight lang=apl inline>Setup</syntaxhighlight> function in that script:
If you want to make sure that all user commands that are Tatin packages are loaded into <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight> at an early stage then add this code to your <syntaxhighlight lang=apl inline>setup.dyalog</syntaxhighlight> script and make sure that it is called by your <syntaxhighlight lang=apl inline>Setup</syntaxhighlight> function:


<syntaxhighlight lang=apl>
<syntaxhighlight lang=apl>
  r←path LoadUserCommandPackages debug;home;name;res;folders;folder;F
  r←path LoadUserCommandPackages debug;home;name;res;folders;folder;F
  ⍝ This loads Tatin packages that are user commands installed in MyUCMDs/
  ⍝ This loads Tatin packages that are user commands installed in "path"
   r←''
   r←''
   F←⎕SE._Tatin.FilesAndDirs
   F←⎕SE._Tatin.FilesAndDirs
   :If 0<≢folders←F.ListDirs path
   :If 0<≢folders←F.ListDirs path
       :For folder :In folders
       :For folder :In folders
           :If F.IsFile folder,'/apl-buildlist.json'
           :If F.IsFile folder,'/apl-buildlist.json'  
               name←2⊃⎕NPARTS folder
               name←2⊃⎕NPARTS folder
               :Trap (~debug)/0
               :Trap (~debug)/0
Line 222: Line 227:
</syntaxhighlight>
</syntaxhighlight>


Note that it uses stuff from Tatin, so it works only with Tatin being available in <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight>, but since you are about to load Tatin packages that must be the case anyway.
== Conclusion ==
 
* Every user command that relies on code that is not part of the user command script as such should check whether that code is already in <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight> and load it into <syntaxhighlight lang=apl inline>⎕SE</syntaxhighlight> if not
* There are good reasons to load all user commands, packaged or otherwise, at an early stage as part of the Dyalog bootstrapping process
* If you have specific user commands that consume a significant amount of memory and are infrequently executed, you can request Dyalog to introduce a mechanism that allows a package to indicate its preference for loading its own code.
 
 
[[Category:Articles]][[Category:Tutorials]][[Category:Dyalog APL examples]]

Latest revision as of 15:48, 7 October 2023

Overview

User commands play a crucial role for Dyalog APL developers. Dyalog comes with a rich set of user commands, but independent parties also develop and maintain user commands. This article discusses how and where to install third-party user commands, and how to load them into ⎕SE.

Prerequisite Knowledge

This article assumes that you are familiar with the concept of Dyalog user commands, and understand what a user command script is, along with its specific features and properties. If you are new to these topics, it is recommended to first study Dyalog's "User Commands User Guide".

Installing user commands

Dyalog installs its own set of user commands into [DYALOG]/SALT/spice. Installing third-party user commands into this folder comes with both advantages and disadvantages.

Advantages of installing into the [DYALOG]/SALT/spice folder:

  • User commands cannot be modified by ordinary users; admin rights are required
  • Every version of Dyalog has its own set of user commands

On the other hand, installing user commands in a different folder, such as MyUCMDs/, has its own advantages:

  • Users have write permission to this folder, making updates easier
  • Anything installed into this folder will be available in all installed versions of Dyalog APL
  • Each user has their own MyUCMDs/ folder, which can be seen as an advantage or disadvantage based on individual preferences


Both the SALT/spice folder and the MyUCMDs/ folder are scanned for user command scripts at startup.

Location of the MyUCMDs/ folder

The location of the MyUCMDs/ folder depends on the operating system used:

  • On Windows it's usually C:\Users\<username>\Documents\
  • On Linux it is /home/<username>/
  • On Mac OS it is /Users/<username>/

Note that MyUCMDs/ is created by the Dyalog APL installer on Windows, but you need to manually create it on non-Windows platforms before version 19.0.

If you have Tatin installed, or you are using version 19.0 or later (those come with Tatin) then you can call this Tatin API function:

      ⎕se.Tatin.GetMyUCMDsFolder'' ⍝ Windows
C:\Users\<username>\Documents\MyUCMDs

Availability of user commands

Once a user command script is moved into the MyUCMDs/ folder (or a sub-folder of it), the user command becomes available across all versions of APL.

For simple user commands where all the code resides in the script itself, this is the end of the process. However, if a user command relies on a larger set of code files that need to be loaded into ⎕SE for execution, additional steps are required.

The user command script could of course check whether the code is already available in ⎕SE and if not load it, and that would work just fine.

User commands with an API

It has become increasingly popular to add an API to user commands. For example, the Dyalog APL project manager Cider offers a rich set of user commands:

 ]cider* -?
                                                                                            
 CIDER:                                                                                     
  CloseProject       Breaks the Link between the workspace and the files on disk            
  CreateProject      Makes the given folder a project folder                                
  Help               Offers to put the HTML files on display                                
  ListAliases        List all defined aliases with their folders                            
  ListOpenProjects   List all currently open projects                                       
  ListTatinPackages  Lists all Tatin packages in all install folders                        
  Make               Build a new version of the project                                     
  OpenProject        Load all source files into the WS and keep it linked by default        
  RunTests           Executes the project's test suite (if any)                             
  Version            Returns name, version number and version date as a three-element vector
  ViewConfig         Puts the config file of a project on display

But Cider also offers an API (public interface):

      ↑⎕se.Cider.⎕nl -3
AddAlias              
CloseProject          
CreateOpenParms       
DropAlias             
GetAliasFileContent   
GetCiderAliasFilename 
GetCiderConfigFilename
GetMyUCMDsFolder      
GetProjectPath        
ListOpenProjects      
ListTatinPackages     
OpenProject           
RenameInfo_url        
RunMake               
RunTests              
Version               
ViewConfig

If you want to use any of the API functions without the need of first calling one of the Cider user commands (that would force the user command loading the code into ⎕SE), then you have to make sure that the code is loaded by other means, ideally at an early stage: as part of the bootstrapping process.


Introducing setup.dyalog in MyUCMDs/

To address this, a script named setup.dyalog is introduced in the MyUCMDs/ folder. When Dyalog encounters this script, it checks for the presence of a function called Setup and executes it.

Notes:

  • The script name must be lowercase to ensure compatibility with non-Windows platforms
  • The script can be a class or a namespace
  • The Setup function must accept a right argument
  • The function Setup must return a result

There is no setup.dyalog yet

Create one that looks like this:

:Namespace SetItUp
    ∇ {r}←Setup arg;⎕IO;⎕ML;dmx
      r←⍬
      ⎕IO←1 ⋄ ⎕ML←1
      :Trap ⎕SE.SALTUtils.DEBUG↓0
          ⎕←LoadMyUserCommand ⎕SE.SALTUtils.DEBUG
      :Else
          dmx←⎕DMX
          ⎕←'Setup.dyalog has a problem and was not executed successfully:'
          ⎕←↑'  '∘,¨dmx.DM
      :EndTrap
    ∇
    ∇ r←LoadMyUserCommand debug;wspath;path2Config
      r←0 0⍴''
      :Trap debug/0
          :If ~IfAtLeastVersion 18
              r←'MyUserCommand  not loaded: not compatible with this version of Dyalog'
          :ElseIf 80≠⎕DR' '              ⍝ Not in "Classic"
              r←'MyUserCommand  not loaded: not compatible with Classic'
          :Else
              ...   ⍝ Load your stuff
          :EndIf
      :Else
          r←'Attempt to load MyUserCommand  failed with ',⎕DMX.EM
      :EndTrap
    ∇
      IfAtLeastVersion←{
      ⍝ ⍵ is supposed to be a number like 15 or 17.1, representing a version of Dyalog APL.
      ⍝ Returns a Boolean that is 1 only if the current version is at least as good.
          ⍵≤{⊃(//)⎕VFI ⍵/⍨2>+\'.'=⍵}2⊃# ⎕WG'APLVersion'
      }
    ∇ r←GetMyUCMDsFolder add
      ⍝ Returns standard path for Dyalog's MyUCMDs folder.\\
      ⍝ Works on all platforms but returns different results.\\
       add←{(((~'/\'∊⍨⊃⍵)∧0≠≢⍵)/'/'),⍵}add
       OS←3↑⊃#.APLVersion
       :If 'Win'≡OS
           r←⊃{⍺,⍵}/1 ⎕nparts (2⊃4070⌶0),'\..\MyUCMDs'
       :Else
           r←(2 ⎕NQ'.' 'GetEnvironment' 'Home'),'/MyUCMDs',add
       :EndIf
    ∇
:EndNamespace

Note that this also checks the version of Dyalog APL and whether it's "Classic" or not. Please customize the script to fit your specific needs. Ensure to modify the IfAtLeastVersion function, if necessary.

If your user command is not a Tatin package then this will do.

There is already a setup.dyalog

Copy the functions IfAtLeastVersion, GetMyUCMDsFolder and LoadMyUserCommand from above into your own setup.dyalog script.

Make sure that LoadMyUserCommand is called from your Setup function.

This makes sure that the API of your user command is available right after instantiating Dyalog APL.

User commands that are Tatin packages

Since version 0.86. 0 a Tatin package can be marked as a user command: by specifying the path to a user command script with a project.

Example:

userCommandScript: "APLSource/MyUserCommand,dyalog",

With this line in the file apl-package.json such a package can be installed and loaded with Tatin:

      ]Tatin.InstallPackages [tatin]MyUserCommand [MyUCMDs]
      ]Tatin.LoadDependencies [MyUCMDs]MyUserCommand

Notes:

  • There is no name specified after [MyUCMDs] in the second argument of InstallPackages: this makes the function use the name of the package for the folder to be created in MyUCMDs/, here MyUserCommand
  • LoadDependencies will look for a folder MyUserCommand in the MyUCMDs/ folder. If there is one, and it contains a file apl-dependencies.txt, then the package will be loaded into ⎕SE.
  • Usually LoadDependencies loads packages into # in case no second argument is specified, but because the folder was specified as an alias ([MyUCMDs]) the function knows that this is about a user command, and therefore the default target for the load operation is ⎕SE rather than #.
  • The user command script MyUserCommand.dyalog is moved to the top of the folder hosting the user command by ]Tatin.Installpackages, here [MyUCMDs]/MyUserCommand

Loading all such user commands

If you want to make sure that all user commands that are Tatin packages are loaded into ⎕SE at an early stage then add this code to your setup.dyalog script and make sure that it is called by your Setup function:

 r←path LoadUserCommandPackages debug;home;name;res;folders;folder;F
 ⍝ This loads Tatin packages that are user commands installed in "path"
   r←''
   F←⎕SE._Tatin.FilesAndDirs
   :If 0<≢folders←F.ListDirs path
       :For folder :In folders
           :If F.IsFile folder,'/apl-buildlist.json' 
               name←2⊃⎕NPARTS folder
               :Trap (~debug)/0
                   {}⎕SE.Tatin.LoadDependencies(path,name)⎕SE
               :Else
                   r,←⊂'>>> Attempt to load ',name,' failed with ',⎕DMX.EM
               :EndTrap
           :EndIf
       :EndFor
   :EndIf
   :If 0=≢r
       r←0 0⍴''
   :Else
       r←⍪r
   :EndIf
 ⍝Done

Conclusion

  • Every user command that relies on code that is not part of the user command script as such should check whether that code is already in ⎕SE and load it into ⎕SE if not
  • There are good reasons to load all user commands, packaged or otherwise, at an early stage as part of the Dyalog bootstrapping process
  • If you have specific user commands that consume a significant amount of memory and are infrequently executed, you can request Dyalog to introduce a mechanism that allows a package to indicate its preference for loading its own code.