Chapter 24: Names and LocalesIn 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 BackgroundIt 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:
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 ExampleSuppose 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.
24.3.1 ReviewWhat 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 LocaleSeveral 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 11000Notice 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. The resulting long list of names can be conveniently displayed with the library-verb list .
list (4 !: 1) 0 1 2 3 NB. show all names in current locale ASSERTING CH IP RUN RUNR TD THIS and cd corr dir drop e first fst hello implies indexfile indexing is_bool is_box is_char is_cmplx is_extint is_float is_int is_list is_number is_rat is_real is_scalar is_string last most not p print pwd rest run s snd take thd yWe can define a new verb, and see its name appear in the list:
foo =: +/ list (4 !: 1) 0 1 2 3 ASSERTING CH IP RUN RUNR TD THIS and cd corr dir drop e first foo fst hello implies indexfile indexing is_bool is_box is_char is_cmplx is_extint is_float is_int is_list is_number is_rat is_real is_scalar is_string last most not p para print pwd rest run s snd take thd yAs 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| +-+-+-+-+-+-+and return to base again
(18 !: 4) < 'base'
24.5 The z Locale Is SpecialThe 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 the name q is not present in the current locale (base):
list (4 !: 1) 0 1 2 3 ASSERTING CH IP RUN RUNR TD THIS and cd corr dir drop e first foo fst hello implies indexfile indexing is_bool is_box is_char is_cmplx is_extint is_float is_int is_list is_number is_rat is_real is_scalar is_string last most not p para print pwd rest run s snd take thd ybut nevertheless we can evaluate the simple name q to get its value as defined in locale z.
q 99Since 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:
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 AssignmentsAn 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_ =: 7creates 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_ =: 2we can survey what we have in locales L and M:
Returning now to the theme of assignments, the scheme is: if the current locale is L, then (foo_M_ =: something) means:
24.6.2 Evaluating NamesNow 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
24.6.3 Applying VerbsConsider 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'
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:
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'
24.6.4 Applying AdverbsSuppose A_X_ is an adverb in locale X. The application of A_X_ to an argument takes place in locale X rather than in the current locale.
To demonstrate this, we start by entering definitions in fresh locales X and Y.
A_X_ =: 1 : 'u & k' NB. an adverb k_X_ =: 17 k_Y_ =: 6now make Y the current locale:
cocurrent 'Y'and apply adverb A_X_ to argument + .
Evidently the result is produced by taking k from locale X rather than from the current locale which is Y.
The scheme is that if the current locale is Y, and A is an adverb, the expression f A_X_ means:
24.7 PathsRecall 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 99Suppose 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.
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.
24.8 Combining Locatives and PathsWe 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 !: 0and then to populate locale Q say, from file economic.ijs, we can write:
POP_Q_ < 'economic.ijs'which works like this:
24.9 Indirect LocativesA 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 6The 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' g k n
24.10 Erasing Names from LocalesSuppose we create a variable with the name var, say,
var =: 'hello'and demonstrate that it exists, that is, that the name var is one of the names in the namelist of the base locale:
(<'var') e. nl_base_ '' 1Now we can erase it with the erase library verb:
erase <'var' 1and demonstrate that it no longer exists
(<'var') e. nl_base_ '' 0Now suppose that we create a variable foo, say, in the base locale, and another, also called foo, in the z locale. Recall that there is always a path from base to z
foo =: 'hello' foo_z_ =: 'goodbye'we demonstrate they both exist:
(<'foo') e. nl_base_ '' 1 (<'foo') e. nl_z_ '' 1erase foo from base, demonstrate that it has gone but that foo in z is still there:
Now if we erase again, foo will be found along the path and erased from z.
This is the end of Chapter 24
Table of Contents
The examples in this chapter
were executed using J version 701.
This chapter last updated 18 Jul 2013
Copyright © Roger Stokes 2013. This material may be freely reproduced, provided that acknowledgement is made.