1
votes

Many times, I attempt to define a macro only to see that it was not created.

  • My first question is: is there a better way to keep track of these failures than manually typing macro list after every single dubious local mylocal ... definition I attempt?

  • Second, why does defining a local ever fail silently? Is there some way to enable warnings for this event?

  • Third, the code below illustrates where this behavior frustrated me most recently: grabbing the position of a word in a string vector; decrementing the position by one; and grabbing the word in the corresponding (immediately preceding) position. Any pointers would be welcome.

.

local  cuts      0 15 32 50
local  mycut     32
local  myposn    : list posof "`mycut'" in cuts

// two methods that fail loudly:
local  mynewcut  : word ``myposn'-1' of cuts

local  mynewcut  : word `myposn'-1 of cuts


// five methods that fail silently, creating nothing:
local  mynewcut  : word `=`myposn'-1' of cuts // 1

scalar tmp = `myposn'
local  mynewcut  : word `=tmp-1' of cuts // 2

scalar tmp2 = tmp -1 // 3 
local mynewcut : word `=tmp2' of cuts

local mynewposn = `=`myposn'-1'
local  mynewcut  : word `mynewposn' of cuts // 4

local  mynewcut  : word `=`mynewposn'' of cuts // 5

// also fails silently (and is not what I'm looking for):
local  mysamecut : word `myposn' of cuts
2

2 Answers

3
votes

This works:

local  cuts      0 15 32 50
local  mycut     32
local  myposn    : list posof "`mycut'" in cuts

local  mynewcut  : word `=`myposn'-1' of `cuts'
display "`mynewcut'"

You need to evaluate the arithmetic operation using =. You are also missing quotes when referring to local cuts.

Trying to use a macro that has not been defined is not considered an error by Stata. This is an element of language design. Also, note that (at least) one of your undesired syntaxes

local  mynewcut  : word `=`myposn'-1' of cuts

is not illegal, so care must be exercised in those cases. After the of, Stata is only expecting some string and cuts is consired a string. This will work just fine:

local  mynewcut  : word 2 of cuts cuts2 cuts3
display "`mynewcut'"

but maybe not as expected. Things change when the quotes are added. Stata now knows it has to do a macro substitution operation.

I usually take a good look at locals before putting them into "production". But you could use assert. For example:

local  cuts      0 15 32 50
local  mycut     32
local  myposn    : list posof "`mycut'" in cuts
display "`myposn'"

local  mynewcut  : word `=`myposn'-1' of cuts
display "`mynewcut'"

assert "`mynewcut'" != ""
3
votes

Roberto gave a good detailed answer, but in addition let's try an overview here. What's crucial is exactly what you understand by fail and whether there is any sense in which Stata might agree with you.

Blanking out an existing local macro and assigning an empty string to a (potential) local macro name have the same effect so far as Stata is concerned. If I go

local foo = 42 
local foo 

or

local bar 

the process is different in kind but the end result is similar. In the first case the local named foo disappears and the second case the local macro bar is never created. The second case is not futile, as (for example) a programmer often wants to make clear that a local macro is initially empty (except that's not quite possible) or that any previously created macro with that name is removed.

More concisely put, Stata doesn't distinguish, at least as far as the user is concerned, between an empty (local or global) macro and a macro that doesn't exist. This is less strange if you understand the definitions here to be inspired by operating system shells, rather than string processing languages.

But there is a useful consequence. The test

if "`bar'" != "" 

is both a test for existence and a test for non-emptiness of the local macro bar, and it applies to macros with numeric characters too.

Furthermore, there may be cases in which you attempt to put a non-empty string into a macro, make some mistake so far as you are concerned, and end by assigning an empty string. That may be a programming mistake, but it's not illegal as far as Stata is concerned, as the examples above already imply.

Completeness is elusive here, but one more case is that a macro definition can be illegal for other reasons. Thus

local foo = lg(42)

will fail because there is no function lg(). On the other hand,

local foo lg(42) 

will succeed so far as Stata is concerned because no evaluation is enforced and so Stata never has to work out lg(42). The macro will just contain lg(42) as text.