Stata 11 help for mf_findexternal

help mata findexternal() -------------------------------------------------------------------------------

Title

[M-5] findexternal() -- Find, create, and remove external globals

Syntax

pointer() scalar findexternal(string scalar name)

pointer() scalar crexternal(string scalar name)

void rmexternal(string scalar name)

string scalar nameexternal(pointer() scalar p)

Description

findexternal(name) returns a pointer (see [M-2] pointers) to the external global matrix, vector, or scalar whose name is specified by name, or to the external global function if the contents of name end in (). findexternal() returns NULL if the external global is not found.

crexternal(name) creates a new external global 0 x 0 real matrix with the specified name and returns a pointer to it; it returns NULL if an external global of that name already exists.

rmexternal(name) removes (deletes) the specified external global or does nothing if no such external global exists.

nameexternal(p) returns the name of *p.

Remarks

Remarks are presented under the following headings:

Definition of a global Use of globals

Also see Linking to external globals in [M-2] declarations.

Definition of a global

When you use Mata interactively, any variables you create are known, equivalently, as externals, globals, or external globals.

: myvar = x

Such variables can be used by subsequent functions that you run, and there are two ways that can happen:

function example1(...) { external real myvar

... myvar ... }

and

function example2(...) { pointer(real) p

p = findexternal("myvar") ... *p ... }

Using the first method, you must know the name of the global at the time you write the source code, and when you run your program, if the global does not exist, it will refuse to run (abort with myvar not found). With the second method, the name of the global can be specified at run time and what is to happen when the global is not found is up to you.

In the second example, although we declared p as a pointer to a real, myvar will not be required to contain a real. After p = findexternal("myvar"), if p!=NULL, p will point to whatever myvar contains, whether it be real, complex, string, or another pointer. (You can diagnose the contents of *p using eltype(*p) and orgtype(*p).)

Use of globals

Globals are useful when a function must remember something from one call to the next:

function example3(real scalar x) { pointer() scalar p

if ( (p = findexternal("myprivatevar")) == NULL) { printf("you haven't called me previously") p = crexternal("myprivatevar") } else { printf("last time, you said "%g", *p) } *p = x }

: example3(2) you haven't called me previously

: example3(31) last time, you said 2

: example3(9) last time, you said 31

Note our use of the name myprivatevar. It actually is not a private variable; it is global, and you would see the variable listed if you described the contents of Mata's memory. Because global variables are so exposed, it is best that you give them long and unlikely names.

In general, programs do not need global variables. The exception is when a program must remember something from one invocation to the next, and especially if that something must be remembered from one invocation of Mata to the next.

When you do need globals, you probably will have more than one thing you will need to recall. There are two ways to proceed. One way is simply to create separate global variables for each thing you need to remember. The other way is to create one global pointer vector and store everything in that. In the following example, we remember one scalar and one matrix:

function example4() { pointer(pointer() vector) scalar p scalar s real matrix X pointer() scalar ps, pX

if ( (p = findexternal("mycollection")) == NULL) { ... calculate scalar s and X from nothing ... ... and save them: p = crexternal("mycollection") *p = (&s, &X) } else { ps = (*p)[1] pX = (*p)[2] ... calculate using *ps and *pX ... } }

In the above example, even though crexternal() created a 0 x 0 real global, we morphed it into a 1 x 2 pointer vector:

p = crexternal("mycollection") *p is 0 x 0 real *p = (&s, &X) *p is 1 x 2 vector

just as we could with any nonpointer object.

In the else part of our program, where we use the previous values, we do not use variables s and X, but ps and pX. Actually, we did not really need them, we could just as well have used *((*p)[1]) and *((*p)[2]), but the code is more easily understood by introducing *ps and *pX.

Actually, we could have used the variables s and X by changing the else part of our program to read

else { s = *(*p)[1] X = *(*p)[2] ... calculate using s and X ... *p = (&s, &X) <- remember to put them back }

Doing that is inefficient because s and X contain copies of the global values. Obviously, the amount of inefficiency depends on the sizes of the elements being copied. For s, there is really no inefficiency at all because s is just a scalar. For X, the amount of inefficiency depends on the dimensions of X. Making a copy of a small X matrix would introduce just a little inefficiency.

The best balance between efficiency and readability is achieved by introducing a subroutine:

function example5() { pointer(pointer() vector) scalar p scalar s real matrix X

if ( (p = findexternal("mycollection")) == NULL) { example5_sub(1, s=., X=J(0,0,.)) p = crexternal("mycollection") *p = (&s, &X) } else { example5_sub(0, (*p)[1], (*p)[2]) } }

function example5_sub(scalar firstcall, scalar x, matrix X) { ... }

The last two lines in the not-found case

p = crexternal("mycollection") *p = (&s, &X)

could also be coded

*crexternal("mycollection") = (&s, &X)

Conformability

findexternal(name), crexternal(name): name: 1 x 1 result: 1 x 1

rmexternal(name): name: 1 x 1 result: void

nameexternal(p): p: 1 x 1 result: 1 x 1

Diagnostics

findexternal(name), crexternal(name), and rmexternal(name) abort with error if name contains an invalid name.

findexternal(name) returns NULL if name does not exist.

crexternal(name) returns NULL if name already exists.

nameexternal(p) returns "" if p=NULL. Also, nameexternal() may be used not just with pointers to globals but pointers to locals as well. For example, you can code nameexternal(&myx), where myx is declared in the same program or a calling program. nameexternal() will usually return the expected local name, such as "myx". In such cases, however, it is also possible that "" will be returned. That can occur because, in the compilation/optimization process, the identity of local variables can be lost.

Source code

Functions are built in.

Also see

Manual: [M-5] findexternal()

Help: [M-5] valofexternal(); [M-4] programming


© Copyright 1996–2009 StataCorp LP   |   Terms of use   |   Privacy   |   Contact us   |   What's new   |   Site index