Content
Why did you create the macro package?
Q: R already has meta-programming capabilities. Why do you want to create a macro programming capability?
A: The macro package was motivated specifically for code generation. The goal is to generate a program where all variable values are resolved, and only the desired conditional code is included in the final program. This result requires a pre-processing and text replacement capability which is lacking in R. The macro package fills that need.
What capabilities does the macro package provide?
Q: It seems the R macro package provides less features than SAS. What capabilities does it provide?
A: The macro package supports the following features:
- Macro Comments
- Macro Variables
- Macro Conditions
- Macro Include
- Macro Do Loops
- User-Defined Macro Functions
- Some Built-In Macro Functions
These features are the most essential features of the SAS macro
language, and will allow you to do most of the things you can do in SAS.
There are many built-in macro functions in SAS that have not been
replicated in the macro package. The built-in macro
functions included in the macro package are
%sysfunc(), %symexist(),
%symput(), and %nrstr().
How does the macro package work?
Q: I don’t quite get it. How am I supposed to use this package?
A: A macro-enabled R program is a standard R
program, with macro commands added as code comments. These special
comments act as pre-processor directives. The pre-processor directives
are resolved by the pre-processor function msource(). What
you will do is write your macro enabled program, and run it with the
msource() function instead of the source()
function. Normally, you will do this on the command line. By default,
the msource() function will run the currently selected
program in RStudio. Otherwise, pass the name of the program you want to
run as the first parameter on msource(). The function will
pre-process the program, resolve any macro statements, and then execute
the resolved code.
Can I create macro functions and do loops?
Q: I want to create a macro function. Does the macro package support it? What about do loops?
A: Yes. The package supports user-defined macro functions and do loops. The syntax is similar to SAS. Note that both of these features are text replacement operations. They are useful specifically when you want to replicate some chunk of code repeatedly. Be mindful of the difference between these macro capabilities and normal Base R functions and loops, and choose your approach appropriately.
Can I nest macro conditionals?
Q: I have a complicated set of conditions that are nested several levels deep. Can I do that with the macro package?
A: Yes. The package supports nested conditionals. There is no limit on the number of nested levels.
How does %include work?
Q: I see from the documentation there is a “%include” macro function. How does it work? Is it the same as SAS?
A: Yes. The “#%include” macro function replicates the basic functionality of SAS “%include”. Text from the included file will be extracted and inserted into the generated file. Any macro statements in the included code will be resolved normally.
What is the difference between symput() and %symput()?
Q: There appears to be two functions,
symput() and %symput(). Why? Don’t they do the
same thing?
A: The symput() and
%symput() functions are similar in that they take a value
from regular R code and assign it to a macro variable. The difference is
in the time they run. The symput() function runs at
execution time, and the %symput() function runs in the
macro pre-processor. This difference is quite significant, and that is
why there are two different functions. The symput()
function can be used in regular R code even before
msource() is called. The %symput() function
can only be used in a macro #%let statement, and will pick
up values dynamically from the generated code.
Why are the debug line numbers off?
Q: I’m trying to debug a macro. But the line numbers on the “In#” column don’t seem to match my program. What is going on?
A: The line numbers shown on the “In#” column represent every input line processed. These lines can come from different sources: the original program, any included code, any macro functions, and code inside do loops. That is why the line numbers do not necessarily match the original program one for one. When trying to find the line that is causing an error, take these additional sources into consideration.
How can I use this package to generate code?
Q: In the documentation you mention that the macro package can be used as a code generator. How does that work?
A: To do code generation, simply supply an output
path as the second parameter on msource(). When the second
parameter is not supplied, the function will create a temporary output
file. When the second parameter is supplied, the function will output
the resolved code to the specified path. That file is the generated
code.
Why should I use this package for code generation?
Q: There are several ways to do code generation in R already. Why would I want to use the macro package?
A: The advantages of using the macro package for code generation are:
- It is easy to combine code from several files using the “#%include” command.
- Only the code inside TRUE macro conditions will be emitted to the output file. This feature makes the resolved code more compact and easier to read.
- Macro variables will be resolved to the actual variable value, instead of the variable name. For instance, a macro variable for a file path will resolve to the actual path, instead of just the variable name. This feature also makes the code easier to read and understand.
- You can write your macro program so that the emitted code runs independently, without any dependencies on external packages, systems, or functions. This feature makes the generated code self-contained, portable, and totally transparent.