Ch 24: Names and Locales

| # Chapter 24: Names and Locales In this chapter we look at locales. The interest of locales is twofold: as a way of organizing large programs, and (as we will come to in the next chapter) as the basis of object-oriented programming in J. ## 24.1 Background It is generally agreed that a large program is best developed in several parts which are, as much as possible, independent of each other. For example, an independent part of a larger program might be a collection of statistical functions, with its own script-file. For the things defined in an independent script, we expect to choose names for those things more or less freely, without regard for what names may be defined in other scripts. Clearly there may be a problem in combining independent scripts: what if the same name accidentally receives different definitions in different scripts? The J facility of the "locale" gives a way to deal with this problem. ## 24.2 What are Locales? After entering an assignment of the form `(name =: something)` we say we have a definition of `name`. Every definition is stored in some region of the memory of the J system called a "locale". Roughly speaking, locales are to definitions as directories are to files. The important features of locales are: There can be several different locales existing at the same time. Each locale stores a collection of definitions. The same name can occur at the same time in different locales with different definitions. Hence a name of the form "name `N` as defined in locale `L`" is uniquely defined, without conflict. Such a name can be written as `N_L_` (N underbar L underbar) and is called a "locative name". Finally At any one time, only one locale is current. The current locale is the one whose definitions are available for immediate use. Hence a plain name `N` commonly means "`N` as defined in the current locale". Locales are neither nouns, verbs, adverbs nor conjunctions: that is, locales are not values which can be assigned to variables or be passed as arguments to functions. They do have names, but whenever we need to refer to a locale by name we do so either with special syntactic forms, (locative names such as `N_L_`) or by quoting the name to form a string. ## 24.3 Example Suppose we are interested in the correlation between the price of whisky and the general level of employee salaries. Suppose also that we have available two scripts, of independent origin, one with economic data and the other with statistical functions. These script-files might have been created like this:
       (0 : 0) (1 !: 2) < 'economic.ijs'
    y  =: 1932  1934  1957  1969  1972   NB. years
    s  =: 1000  1000  3000  9000 11000   NB. salaries
    p  =: 1.59  1.68  2.00  4.50  5.59   NB. prices
    )

       (0 : 0) (1 !: 2) < 'statfns.ijs'
    m =: +/ % #        NB.  Mean
    n =: - m           NB.  Norm
    v =: m @: *: @: n  NB.  Variance
    s =: %: @: v       NB.  Standard Deviation
    c =: m @: (*&n)    NB.  Covariance
    r =: c % (*&s)     NB.  Correlation Coefficient
    )
We aim to load these two scripts, and then hope to compute the coefficient of correlation between prices `p` and salaries `s` as the value of the expression `(p r s)`. Unfortunately we can see that the name `s` means different things in the different scripts. If we were to load both scripts into the same locale, one definition of `s` would overwrite the other. The remedy is to load the two scripts into different locales. There is always a locale named `base`, and by default this is usually current. We load `economic.ijs` into the current locale (`base`) with the built-in verb `(0 !: 0)`.
       (0 !: 0) < 'economic.ijs'
Next we load `statfns.ijs` into another locale which we choose to call, say, `stat`. To do this with the minimum of new apparatus we can use the built-in verb `(18 !: 4)`.
       (18 !: 4) < 'stat'
       (0 !: 0)  < 'statfns.ijs'
       (18 !: 4) < 'base'
The first line creates the `stat` locale and makes it current. The second line loads `statfns.ijs` into the now-current locale `stat`. The third line makes the `base` locale current again, to restore the status quo. At this point our data variables `s` and `p` are available because they are in `base` which is current. The correlation-coefficient function `r` is not yet available, because it is in `stat` which is not current. The next step is to define the correlation-coefficient function to be `r`-as-defined-in-locale- `stat`, using the locative form of name `r_stat_`
       corr =: r_stat_
`corr` is available because it has just been defined in `base` (because `base` is current). Everything we need is now available. We can compute the correlation between salaries and prices.
`s corr p` | `p corr s` | `p corr p`
    0.993816
    0.993816
    1
### 24.3.1 Review What we have seen is the use of locative names to resolve name-conflicts between independent scripts. What it took was a relatively small amount of ad-hoc further definition. In this tiny example the conflict was easily identified and could be easily fixed by editing one of the scripts. However, the point is that we aim to avoid tampering with independent scripts to get them to work together. ## 24.4 The Current Locale Several locales may coexist, but at any one time only one is current. There is a built-in verb (18 !: 5) which tells us the name of the current locale.
       (18 !: 5) ''  NB. show name of current locale
    +----+
    |base|
    +----+
The significance of the current locale is that it is in the current locale that simple names are evaluated:
       s
    1000 1000 3000 9000 11000
Notice that we get the value of `s` as defined in script `economic.ijs` which we loaded into `base`, and not the value of `s` in `statfns.ijs` which was loaded into locale `stat`. It is the current locale in which new definitions are stored. To see what names are defined in the current locale we can use the built-in verb `(4 !: 1)` with an argument of `0 1 2 3`.
       (4 !: 1) 0 1 2 3  NB. show all names in current locale
    +----+-+-+-+--+
    |corr|p|s|y|y.|
    +----+-+-+-+--+

       foo  =: +/
       (4 !: 1) 0 1 2 3
    +----+---+-+-+-+--+
    |corr|foo|p|s|y|y.|
    +----+---+-+-+-+--+
As we saw above, we can change the current locale with the built-in verb `(18 !: 4)`. We can make the `stat` locale current with:
       (18 !: 4) < 'stat'
and now we can see what names are defined in this locale with:
       (4 !: 1) 0 1 2 3
    +-+-+-+-+-+-+--+
    |c|m|n|r|s|v|y.|
    +-+-+-+-+-+-+--+
and return to `base` again
       (18 !: 4) < 'base'
## 24.5 The z Locale Is Special The locale named `z` is special in the following sense. When a name is evaluated, and a definition for that name is not present in the current locale, then the `z` locale is automatically searched for that name. Here is an example. We put into locale`z` a definition of a variable `q`, say.
       (18 !: 4) < 'z'
       q =: 99
       (18 !: 4) < 'base'
Now we see that `q` is not present in the current locale (`base`) but nevertheless we can evaluate the simple name `q` to get its value as defined in locale `z`.
       (4 !: 1) 0 1 2 3
    +----+---+-+-+-+--+
    |corr|foo|p|s|y|y.|
    +----+---+-+-+-+--+
       q
    99
Since we can find in `z` things which are not in `base`, locale `z` is the natural home for functions of general utility. On starting a J session, locale `z` is automatically populated with a collection of useful predefined "library" functions. The names of these functions in the `z` locale are all available for immediate use, and yet the names, of which there are more than 100, do not clutter the `base` locale. We saw above the use of built-in verbs such as `(18 !: 4)` and `(4 !: 1)`. However the library verbs of locale `z` are often more convenient. Here is a small selection:
`coname ''` | show name of current locale
`conl 0` | show names of all locales
`names ''` | show all names in current locale
`nl ''` | show all names in current locale (as a boxed list)
`cocurrent 'foo'` | locale `foo` becomes current
`clear 'foo'` | remove all defns from locale `foo`
`coerase 'A';'B';'C'` | erase locales `A` `B` and `C`
We have seen that when a name is not found in the current locale, the search proceeds automatically to the `z` locale. In other words, there is what is called a "path" from every locale to the `z` locale. We will come back to the subject of paths below. ## 24.6 Locative Names and the Evaluation of Expressions ### 24.6.1 Assignments An assignment of the form `n_L_ =: something` assigns the value of `something` to the name `n` in locale `L`. Locale `L` is created if it does not already exist. For example:
       n_L_ =: 7
creates the name `n` in locale `L` with value `7`. At this point it will be helpful to introduce a utility-function to view all the definitions in a locale. We put this `view` function into locale `z` :
       VIEW_z_ =: 3 : '(> ,. ('' =: ''&,)@:(5!:5)"0) nl '''''
       view_z_ =: 3 : 'VIEW__lo '''' [ lo =. < y.'
If we make a few more definitions:
       k_L_ =: 0
       n_M_ =: 2
we can survey what we have in locales `L` and `M`:
`view 'L'` | `view 'M'`
    k =: 0
    n =: 7
    n =: 2
Returning now to the theme of assignments, the scheme is: if the current locale is `L`, then `(foo_M_ =: something)` means: evaluate `something` in locale `L` to get value `V` say. `cocurrent 'M'` `foo =: V` `cocurrent 'L'` For example:
       cocurrent 'L'
`view 'L'` | `view 'M'` | `k_M_ =: n-1` | `view 'M'`
    k =: 0
    n =: 7
    n =: 2
    6
    k =: 6
    n =: 2
### 24.6.2 Evaluating Names Now we look at locative names occurring in expressions. The scheme (call this scheme 2) is: if the current locale is `L` then `(n_M_)` means `cocurrent 'M'` evaluate the name `n` to get a value `V` `cocurrent 'L'` `V` For example:
       cocurrent 'L'
`view 'L'` | `view 'M'` | `n_M_`
    k =: 0
    n =: 7
    k =: 6
    n =: 2
    2
### 24.6.3 Applying Verbs Consider the expression `(f_M_ n)`. This means: function `f` (as defined in locale `M`) applied to an argument `n` (as defined in the current locale) In this case, the application of `f` to `n` takes place in locale `M`. Here is an example:
       u_M_ =: 3 : 'y.+k'

       cocurrent 'L'
`view 'L'` | `view 'M'` | `u_M_ n`
    k =: 0
    n =: 7
    k =: 6
    n =: 2
    u =: 3 : 'y.+k'
    13
We see that the argument `n` comes from the current locale `L`, but the constant `k` comes from the locale (`M`) from which we took verb `u`. The scheme (call it scheme 3) is: if the current locale is `L` , then `(f_M_ something)` means: evaluate `something` in `L` to get a value `V` say `cocurrent 'M'` in locale `M`, evaluate the expression `f V` to get a value `R` say `cocurrent 'L'` `R` Here is another example. The verb `g` is taken from the same locale in which `f` is found:
       g_L_ =: +&1
       g_M_ =: +&2
       f_M_ =: g

       cocurrent 'L'
`view 'L'` | `view 'M'` | `f_M_ k`
    g =: +&1
    k =: 0
    n =: 7
    f =: g
    g =: +&2
    k =: 6
    n =: 2
    u =: 3 : 'y.+k'
    2
### 24.6.4 Applying Adverbs To begin, note that when an adverb is applied, names of verbs do not get evaluated.
`w =: +` | `z =: *` | `ADV =: @: z` | `w ADV`
    +
    *
    @:z
    w@:z
The result is an expression for a verb in terms of `w`, the argument, and `z` which occurrs in the definition of `ADV` Here now is an example of an adverb referred to by a locative name. We enter definitions in fresh locales `P` and `Q`.
       u_P_ =: *&2
       v_P_ =: *&3
       u_Q_ =: *&7
       v_Q_ =: *&5
       A_Q_ =: @: v
make `P` the current locale, and apply adverb `A_Q_` to argument `u` to get verb `D`:
       cocurrent 'P'
`view 'P'` | `view 'Q'` | `D =: u A_Q_` | `D 1`
    u =: *&2
    v =: *&3
    A =: @:v
    u =: *&7
    v =: *&5
    u@:v
    6
Evidently the result `6` is obtained by taking `u` and `v` from the current locale which is `P`. The scheme is that if the current locale is `P`, and `A` is an adverb, the expression `u A_Q_` means: evaluate `u` in locale `P` to get a value `U` say. (and if `u` is the name of a verb, then the result `U` is just `u`.) cocurrent `Q` evaluate `U A` in locale `Q`. The result is a verb, `D` say, defined in terms of named verbs (`u` and `v` in this example.) cocurrent `P` `D` We can demonstrate that the evaluation of `u A_Q_` takes place in locale `Q` by forcing all named verbs to be evaluated. We apply the "fix" adverb to disclose the definitions of the named verbs.
       B_Q_ =: (@: v) f.
`view 'P'` | `view 'Q'` | `D =: u B_Q_` | `D 1`
    D =: u@:v
    u =: *&2
    v =: *&3
    A =: @:v
    B =: (@:v) f.
    u =: *&7
    v =: *&5
    *&7@:(*&5)
    35
Evidently the argument `u` and the auxiliary verb `v` are both taken from locale `Q`. ## 24.7 Paths Recall that the `z` locale contains useful "library" functions, and that we said there is a path from any locale to `z`. We can inspect the path from a locale with the library verb `copath`; we expect the path from locale `base` to be just `z`.
       copath 'base'   NB. show path
    +-+
    |z|
    +-+
A path is represented as a (list of) boxed string(s). We can build our own structure of search-paths between locales. We will give `base` a path to `stat` and then to `z`, using dyadic `copath`.
       ('stat';'z') copath 'base'
and check the result is as expected:
       copath 'base'
    +----+-+
    |stat|z|
    +----+-+
With this path in place, we can, while `base` is current, find names in `base`, `stat` and `z`.
       cocurrent 'base'

       s     NB. in base
    1000 1000 3000 9000 11000

       r     NB. in stat
    c % *&s

       q     NB. in z
    99
Suppose we set up a path from `L` to `M`. Notice that we want every path to terminate at locale `z`, (otherwise we may lose access to the useful stuff in `z`) so we make the path go from `L` to `M` to `z`.
       ('M';'z') copath 'L'
If we access a name along a path, there is no change of current locale. Compare the effects of referring to verb `u` via a locative name and searching for `u` along a path.
       cocurrent 'L'
`view 'L'` | `view 'M'` | `u_M_ 0` | `u 0`
    ADV =: @:z
    g   =: +&1
    k   =: 0
    n   =: 7
    w   =: +
    z   =: *
    f =: g
    g =: +&2
    k =: 6
    n =: 2
    u =: 3 : 'y.+k'
    6
    0
We see that in evaluating `(u_M_ 0)` there is a change of locale to `M`, so that the variable `k` is picked up with its value in `M` of 6. In evaluating `(u 0)`, where `u` is found along the path, the variable `k` is picked up from the current locale, with its value in `L` of `0`. When a name is found along a path, it is as though the definition were temporarily copied into the current locale. Here is another example.
`view 'L'` | `view 'M'` | `f_M_ 0` | `f 0`
    ADV =: @:z
    g   =: +&1
    k   =: 0
    n   =: 7
    w   =: +
    z   =: *
    f =: g
    g =: +&2
    k =: 6
    n =: 2
    u =: 3 : 'y.+k'
    2
    1
## 24.8 Combining Locatives and Paths We sometimes want to populate a locale with definitions from a script-file. We saw above one way to do this: in three steps: (1) use `cocurrent` (or `18!: 4`) to move to the specified locale. (2) execute the script-file with `0!:0` (3) use `cocurrent` (or `18!:4`) to return to the original locale. A neater way is as follows. We first define:
       POP_z_ =: 0 !: 0
and then to populate locale `Q` say, from file `economic.ijs`, we can write:
       POP_Q_ < 'economic.ijs'
which works like this: The `POP` verb is defined in locale `z`. Encountering `POP_Q_ < ...` the system makes locale `Q` temporarily current, creating `Q` if it does not already exist. The system looks for a definition of `POP`. It does not find it in `Q` , because `POP` is of course defined in locale `z`. The system then looks along the path from `Q` to `z` and finds `POP`. Note that the current locale is still (temporarily) `Q`. The `POP` verb is applied to its argument, in temporarily-current locale `Q`. The current locale is automatically restored to whatever it was beforehand. Back to base. (If we are nipping about between locales it is advisable to keep track of where we are.)
       cocurrent <'base'
## 24.9 Indirect Locatives A variable can hold the name of a locale as a boxed string. For example, given that `M` is a locale,
       loc =: < 'M'
Then a locative name such as `k_M_` can be written equivalently in the form `k__loc` (u underscore underscore loc)
       k_M_
    6

       k__loc
    6
The point of this indirect form is that it makes it convenient to supply locale-names as arguments to functions.
       NAMES =: 3 : 0
    locname =. < y.
    names__locname ''
    )

       NAMES 'L'
    ADV g   k   n   w   z
This is the end of Chapter 24

NEXT
Table of Contents
Index

Copyright © Roger Stokes 2003. This material may be freely reproduced, provided that this copyright notice is also reproduced.

last updated 31 May 2003