Lately I have been writing a lot of modular Stata code, where bits and pieces of the job are done by separate programs, sometimes declared in different do-files (called in with do). You get programs to pass on things to each other by making them rclass. Now, r() results can be scalars as in this example, or locals. The latter are convenient because they can accommodate strings as easily as numbers, but they can trip you up.

See, Stata locals are just strings that come with a reasonable kind of automatic type conversion designed to make your life easier: if your string consists of numbers only, it will be evaluated. For example, local a=1 and local a 1 have the same effect: display `a' will return 1, the number, in either case.

But there is a subtle difference between an empty local with a name and a missing local. Stata, in a pinch, will identify either as a missing value, and that may work for you most of the time. But only the former can be called in a numeric expression that relies on automatic type conversion. The latter will give you a "missing name" error. Below is a simple example:

capture prog drop myLocal
prog def myLocal, rclass

local a
return local myresult `a'

end

myLocal
local a `r(myresult)' // note (1): this will work fine

if `a'==. {
  di "local a is missing"
}
else {
  di `a'
}

The code above will abort with the error message "nothing found where name expected r(198);", but that error message won't come at the definition of local a commented with note (1). That definition will work as if everything were fine: it simply returns a missing value. It's when you're calling the subsequent if-condition that you run into trouble.

The solution is to make sure that myLocal is returning what you mean it to. If you want it to return a missing numeric value, this is the way to go:

capture prog drop myLocal
prog def myLocal, rclass

local a=.
return local myresult `a'

end

myLocal
local a `r(myresult)'

if `a'==. {
  di "local a is missing"
}
else {
  di `a'
}

If instead you want to return a missing string, you need to make sure that your if-condition is a string condition:

capture prog drop myLocal
prog def myLocal, rclass

local a
return local myresult `a'

end

myLocal
local a `r(myresult)'

if "`a'"=="" {
  di "local a is missing"
}
else {
  di `a'
}

This is not as pointless as it looks. You seldom want programs to return a missing value as a result, of course. But a missing value can sometimes be a legitimate member of the set of possible results. When you run into one, you need a way to handle it.