Day 15 of 30·Functions & Macro-like Behavior
Reusable Code: Scripts, Packages & Defensive Programming
Organizing functions, adding checks, and structuring a study codebase.
Learning objectives
- 1Organize helper functions into sourced scripts or a study package.
- 2Add input checks with stopifnot() and assertions.
- 3Write informative errors and warnings.
- 4Understand why packaged, tested functions aid validation.
Key SAS® → R comparison
| Task | SAS® | R |
|---|---|---|
| Shared macros | %include / autocall library | source('utils.R') / a package |
| Input check | %if / error in macro | stopifnot() / if(!...) stop() |
| Message | put 'WARNING:'; | warning() / message() |
Code examples
SAS®
%macro chg(base, post);
/* limited validation available */
%mend;R
chg <- function(post, base) {
stopifnot(is.numeric(post), is.numeric(base))
post - base
}Note: stopifnot() fails fast with a clear message if inputs aren't what you expect — cheap insurance in a regulated pipeline.
Explanation
As a study grows, functions belong in sourced utility scripts or, better, a small internal package, so they are versioned, documented and unit-tested. This is the open-source analog of an autocall macro library, but with far stronger tooling for testing and review.
Defensive checks — verifying types, lengths and expected values up front — turn silent data errors into immediate, informative failures, which is exactly what validation and QC reviewers want to see.
Practice exercise
Collect three derivation helpers into a utils.R, add stopifnot() input checks to each, source the file, and write a tiny test that confirms each returns the expected value.