3

I'm using SAS' PROC FCMP to write some functions for recoding. These will be saved in a data set in a shared directory, so my coworkers can use them. Most of the time, the functions are just wrappers that hash a look-up table in the same directory.

Simplified example:

Libname OurStuff "path/to/shared/data";

DATA OurStuff.foobar;
    foo = 1;
    bar = 2;
Run;

PROC FCMP outlib = OurStuff.functions.lookup;
    Function recode_foo(foo);
        Length bar 8;
        Declare hash foobar(dataset: "OurStuff.foobar");
        rc = foobar.defineKey("foo");
        rc = foobar.defineData("bar");
        rc = foobar.defineDone();
        rc = foobar.find();
        Return(bar);
    Endsub;
Run;

The function works with the original libname:

Options cmplib = OurStuff.functions;
DATA _NULL_;
    result = recode_foo(1);
    Put result =;
Run;

But if somebody uses a different libname, it won't:

Libname OurStuff clear;
Libname WildName "path/to/shared/data";
Options cmplib = WildName.functions;

/* Results in "ERROR: Libref OURSTUFF is not assigned" */
DATA _NULL_;
    result = recode_foo(1);
Run;

Is there a way, other than insisting everyone uses the same libnames, to make sure these functions always work?

Nathan Werth
  • 5,093
  • 18
  • 25

1 Answers1

3

Since dataset is a string, it can be determined at runtime. Thus, you can pass it as a parameter to the function - either the libname, or (better) the whole dataset string.

PROC FCMP outlib = OurStuff.functions.lookup;
    Function recode_foo(foo,dset $);
        Length bar 8;
        Declare hash foobar(dataset: dset);
        rc = foobar.defineKey("foo");
        rc = foobar.defineData("bar");
        rc = foobar.defineDone();
        rc = foobar.find();
        Return(bar);
    Endsub;
Run;
Joe
  • 62,789
  • 6
  • 49
  • 67
  • 1
    Need $ after DSET in FUNCTION statement. – Tom Sep 21 '16 at 21:03
  • @Tom Good catch - one reason I prefer runnable examples (I'll make one when I have a sec) – Joe Sep 21 '16 at 21:03
  • @Joe That answer would work, but I was hoping for something more elegant than adding an extra argument to every lookup function. Since the data set names are reliable, I think providing the library housing the data would be enough: `Function recode_foo(foo, lib $)`. This way, I can also pass the library to nested functions that also need to know where to look. – Nathan Werth Sep 22 '16 at 13:11