Namespaces
Namespaces#
Let’s create the simplest APL type of object Dyalog APL has, the namespace. APLWiki has a good intro. A namespace is like a container for other APL items (functions, variables, and namespaces). It is very much like a JSON object.
One way to create a new empty namespace is using the system function ⎕NS
. For now, we’ll just use a dummy right argument; ⍬
. To assign into a namespace we use the dot-notation: namespace.name←value
. Same goes when we want to query the value.
b←a←⎕NS ⍬
a.var←52
b.var←42
a.var b.var
42 42
We created the namespace a
. Then we used its value to set b
, then we set var
inside a
and inside b
to two different values, but when we queried the two values they had become the same (the latter). This is because APL objects are mutable. Another way to look at it is that the value isn’t really the namespace itself, but rather a reference to a single object we created with a single call to ⎕NS
.
b a←⎕NS¨ ⍬ ⍬
a.var←52
b.var←42
a.var b.var
52 42
Here we called ⎕NS
twice, once on each of the two ⍬
s. And so b
and a
refer to two different objects. Also note that there is no assignment arrow between b
and a
, but don’t be fooled:
b a←⎕NS ⍬
a.var←52
b.var←42
a.var b.var
42 42
The last 42 42
result is of course (!) because of APL’s scalar extension (vectorisation/mapping/…). Refs are scalar values, and so the scalar was distributed to both names, just like b a←42
would have done.
You can also put functions inside a namespace:
ns←⎕NS ⍬
ns.fn←{'hello' ⍵}
ns.fn 'world'
┌─────┬─────┐ │hello│world│ └─────┴─────┘
All APL built-ins exist (separately!) in every namespace.
a b←⎕NS¨⍬⍬
a.⎕IO←0
b.⎕IO←1
a.⍳ 5
b.⍳ 5
0 1 2 3 4
1 2 3 4 5
Here is another way to create a namespace:
ns←⎕JSON '{"a":52, "b":42}'
ns.a
ns.b
52
42
We can, of course, also use ⎕JSON
to visualise (simple) APL objects:
a←⎕NS ⍬ ⋄ a.(x y z)←1 2 'Brian'
⎕JSON a
{"x":1,"y":2,"z":"Brian"}
Namespaces are great ways to organise you code and data. But sometimes you need a better overview of the namespace content, or you want to put tradfns there (in an easy manner) or even put some comments in. To help you manage larger namespaces and especially code in namespaces, you can have a scripted namespace. The script is a simple text document which gets “fixed” into a namespace, much like the JSON text got converted to an APL object.
This uses a syntax similar to the tradfn control structures, namely :Namespace … :EndNamespace
:
⎕FIX ':Namespace a' 'var←42' ':EndNamespace'
a.var
42
Of course, the ⎕FIX
usage is even more cumbersome (except possibly when you need to define namespaces under program control), but in an interactive APL session, you can enter )ed ⍟nyns
to open the editor with a new namespace script. In a Jupyter notebook cell you can create a scripted namespace using ]dinput
:
]dinput
:Namespace b
var←43
:EndNamespace
b.var
43
Here’s a scripted namespace with a few things in it; a variable, a dfn, and a tradfn:
]dinput
:Namespace ns
var←42
dfn←{
'the argument:' ⍵
}
∇ r←tradfn x
r←?x
∇
:EndNamespace
var←77
⎕NL -⍳9
ns.⎕NL -⍳9
var ns.var
┌─┬─┬──┬───┐ │a│b│ns│var│ └─┴─┴──┴───┘
┌───┬──────┬───┐ │dfn│tradfn│var│ └───┴──────┴───┘
77 42
We first ask for the Name List in #
(the root namespace) and again inside ns
and then we retrieve the value of #.var
and ns.var
.
By the way, from inside a namespace, you can access the parent namespace with ##
and its parent with ##.##
etc. #
doesn’t have a parent though, so #.##
is the same as #
. This of course implies that you can nest namespaces. And indeed, you can even do so inside a script:
]dinput
:Namespace ns
variable←42
dfn←{
'the arguments:'⍺ ⍵
}
:Namespace inner
∇ r←tradfn x
r←?x
∇
:EndNamespace
:EndNamespace
ns.inner.tradfn 3
3