Do-file rules, revisited
Tuesday, 22 May 2012
Back in 2009 I wrote this post, detailing what at the time I thought would be a good way to write do-files. Some of the ideas there have stood the test of time. Others haven't. The changes are driven by Stata's evolution, by new things I've learned and by ways that my work changed. This is a quick review.
First, as of Stata 12, you don't need to
set memory anymore. Second,
clear should now be replaced by
clear all. In addition, J. Scott Long recommends that you type
macro drop _all right after it. I know this because I'm reading his Workflow book right now. I know I'm three years late (two if you count from where one of this blog's readers recommended it to me for the first time). I'm still finding useful stuff there. Next, as Jess suggested in the comments thread to the original post, I now use
set varabbrev off.
Finally, my do-files no longer have a Globals section. Instead, there's now a program that defines all macros in one place as local macros and returns them. I first started doing this back in 2010, as detailed here. At the time it seemed like a slick thing to do. I just assumed, wrongly, that this would be faster at execution time than the original solution that gave me the idea (using a separate do-file, called with
The staying power of having a program for defining locals came not from its execution speed, but from its versatility. You can define all the locals you want inside a program you call, say,
setLocals. If you need more locals as the requirements for your code grow, you just pile them on inside this program, and remember to also return them.
Then, whenever any specific local macro is needed, you call setLocals and only recover the `r()' value that you need then. Locals can be substituted for the obvious things -- like operating system-specific file paths or hard-coded numbers -- and also for names of programs you define somewhere else. This will also spare you the inconvenience of reading a do-file where
`this' local shows up all of a sudden and if it's not obvious what it holds, you must work your way up to see where it was defined: if all locals are defined in setLocals, you will always know where to look.
This is probably a terrible way to use memory, but the convenience of having all my locals defined in one place and any arbitrary subset of them available with the same simple call to setLocals is well worth it. You can extend this model in all sorts of ways, with some care. You can, for example, give setLocals an optional argument (using something as flexible as
syntax [anything]) so its behavior is changed according to whether the argument is present. For example, a call to
setLocals on its own will return a default set of local macros that apply everywhere; a call to
setLocals andAlsoTheseOtherLocals will return the default macros plus a set defined inside a second program, andAlsoTheseOtherLocals, to be used in some specific context.