Title | Syntax for allowing alternative types of arguments to program options | |
Authors |
Nicholas Winter, University of Virginia Michael Blasnik, Blasnik & Associates Nicholas J. Cox, Durham University, UK |
I want to use syntax with an option, call it x1(), which will be allowed to be either a real number or a numeric variable. Is there an easy way to do this?
Concretely, these two forms should be combined into one:
syntax, x1(real) syntax, x1(varname numeric)
The short answer is that there are several ways to do it. Below, we outline and exemplify three solutions. For background, see help syntax, capture, and confirm or [P] syntax, [P] capture, and [P] confirm.
Get x1() as a string, and then test it after your syntax line:
syntax , x1(string) capture confirm variable `x1' if _rc { capture confirm number `x1' if _rc { di as error "x1() must be a new variable name or a number" error 198 } else local isvar 0 } else local isvar 1
This also sets the local macro isvar to indicate if x1() specified a variable name or a number in case you need to take different action for each.
If the syntax included other elements, they can be included in the syntax statement as usual.
capture syntax , x1(real) if _rc capture syntax, x1(varname numeric) else local isvar 0 if _rc { di as err "x1() must be a new variable name or a number" exit 198 } else local isvar 1
That is, if one syntax does not fit, the other one must.
This also sets the local macro isvar to indicate if x1() specified a variable name or a number in case you need to take different action for each.
If the syntax included other elements,
capture syntax ... , x1(real) ... if _rc { syntax ... , x1(varname numeric) ... local isvar 1 } else local isvar 0
If the problem is with what was in x1(), then the user will get a message to that effect. If the problem lies with other stuff, then there will be a message to that effect. The only loss is a little informativeness.
To get two types of behavior from the same option, type
syntax [, X1a(real 0) X1b(varname numeric)] local nopts = (`x1a' != 0) + ("`x1b'" != "") if `nopts' == 0 { di as err "x1() option required" exit 198 } else { local isvar = "`x1b'" != "" local x1 = cond(`isvar', "`x1b'", "`x1a') }
This also sets the local macro isvar to indicate if x1() specified a variable name or a number in case you need to take different action for each.
The online help should just list a single option named x1(), flagging the fact that different types of arguments are acceptable. Here, you are exploiting that Stata allows option names to have the same abbreviation, as long as the full option name differs. syntax will then parse what the user types as you wish.
Note that since x1a() is not a required option, it will return a default value (0 in the example). In some problems, only certain values make sense (say, positive values). Setting a default value that makes no sense allows you to distinguish between what the user typed and the default. Trickier circumstances can be dealt with by specifying that x1a() takes a numlist with particular properties.
Alternatively, if there is a natural default number for x1() (again, for example, 0), then the code can be based on
syntax [, X1a(real 0) X1b(varname numeric)] local isvar = "`x1b'" != "" local x1 = cond(`isvar', "`x1b'", "`x1a')
However, as above, because two options are allowed, it is possible that a user might specify both of them, presumably by accident, and careful code will trap this.
If the syntax includes other elements, they can be included in the syntax statement as usual.
Note: The order of the authors’ names was determined by a random shuffle in Stata of their surnames from alphabetical order after set seed 123456789.