Introduction
Keyword procedure arguments, introduced in GAUSS 26.1, give you the ability to write cleaner code that is more concise, easier to write, and easier to read. Just as importantly, they are intuitive enough that you can start using them immediately. Today we'll show you everything you need to know to make your work easier right away.
Self-documenting Code with Keyword Inputs
GAUSS has long had optional inputs, so you did not have to pass in every possible input. However, they were positional inputs. Positional inputs have to be passed in a specific order. So if you wanted to use the seventh input, you would have to pass in all seven--and remember which order to pass them in.
For example, let's consider a hypothetical procedure named myEstimate() that fits an ARDL-style model and takes:
- y - Time series vector.
- X - Exogenous variables.
- y_lags - Set of lags of the dependent variable to include in the estimation. Default = {}, no y-lags.
- X_lags - Set of lags of the exogenous variables to include in the estimation. Default = {}, no X-lags.
- const - 0, no constant. 1, include a constant. Default = 1.
- trend - 0, no trend. 1, include a trend. Default = 0.
- quiet - 1, no output report. 0, print an output summary. Default = 0.
// Before — to set quiet, you have to pass everything ahead of it
result = myEstimate(y, X, {1 2}, {}, 1, 0, 1);
can be written as:
// Using keyword inputs
result = myEstimate(y, X, y_lags={1 2}, quiet=1);
// Keyword inputs can be in any order
result = myEstimate(y, X, quiet=1, y_lags={1 2});
As we see above, the keyword input version:
- Is concise and readable.
- Does not require you to remember the input order.
- Does not make you set inputs, like trend, that you want to leave at the default setting.
Adding Keyword Inputs to Your Own Procedures
Next we'll convert the following simple simulation procedure to use keyword inputs.
proc (1) = simulate(nrows, ncols, mu, sd);
local X;
X = (rndn(nrows, ncols) * sd) + mu;
retp(X);
endp;
Declaring Keyword Inputs
To convert the inputs to simulate() to keyword arguments, all we need to do is add an equals sign and the default value after the input in the procedure definition.
proc (1) = simulate(nrows=5, ncols=1, mu=0, sd=1);
local X;
X = (rndn(nrows, ncols) * sd) + mu;
retp(X);
endp;
Now we can call our procedure with no inputs if we want:
// Set for repeatable random numbers
rndseed 23423;
print simulate();
0.4372582
-0.3276965
0.9718211
-0.0842395
-0.3505402
What Can be a Default Value
Default values can be any literal value of any data type. They can be scalars as in our previous example, matrices, strings, or string arrays.
| Default Type | Example | Notes |
|---|---|---|
| Scalar | sd = 1, tol = -2.5e-3 |
Integers, decimals, and scientific notation |
| Vector or matrix | mu = {0 100}, w = {1 2, 3 4} |
Spaces separate columns, commas separate rows |
| String | dist = "normal" |
Enclosed in double quotes |
| String array | names = {"y1", "y2"} |
Produces a true string array |
| Empty matrix | xreg = {} |
The standard way to mark an input as "not supplied" |
What Cannot be a Default Value
| Not Allowed | Example | Why |
|---|---|---|
| Variables | a = n |
Defaults are stored as source text, so they can't reference other symbols |
| Expressions | a = n*2, k = 1+1 |
Operators are not permitted in a default |
| Reserved words as inputs | trim = 0, output = 1 |
Input names can't shadow a GAUSS command or function |
Calling a Procedure with Keyword Inputs
Rules for Calling a Procedure with Keyword Inputs
- Positional inputs come first. Once you pass an input by name, every input after it must also be passed by name.
- Only inputs with a default can be passed by name. An input declared without a default is positional-only.
- Named inputs can appear in any order.
- Any named input you leave out uses its default.
Mixing Positional and Keyword Inputs
Coming back to our opening example:
result = myEstimate(y, X, y_lags={1 2}, quiet=1);
y and X are passed by position, everything else is by name. Since there is no sensible default for your data, they should be required. Inputs declared without a default are positional inputs. They must be passed in before any keyword inputs and they have to be passed in the order the procedure declares them.
Let's continue with a modified version of our simulate() procedure, because it's short and simple.
// Simulate with 1 required positional input
proc (1) = simulate(nrows, ncols=1, mu=0, sd=1);
local X;
X = (rndn(nrows, ncols) * sd) + mu;
retp(X);
endp;
// For repeatable random numbers
rndseed 23423;
print simulate(3, sd=2.5);
1.0931455
-0.81924125
2.4295527
Keyword inputs can also be passed by position, so all of the following calls are equivalent:
rndseed 23423;
print simulate(3, sd=2.5);
rndseed 23423;
print simulate(3, 1, 0, sd=2.5);
rndseed 23423;
print simulate(3, 1, 0, 2.5);
1.0931455
-0.81924125
2.4295527
1.0931455
-0.81924125
2.4295527
1.0931455
-0.81924125
2.4295527
If you misspell the name of a keyword input, GAUSS suggests the closest match:
// Incorrect: error G0739 : Unknown keyword argument 'ncol (did you mean ncols?)'
x = simulate(3, ncol=2);
However, here are two things to watch out for. First, once you name an input, everything after must be named:
// Incorrect: error G0741 : Positional argument after keyword argument
x = simulate(3, ncols=1, 0);
Second, a positional input can't be passed by name:
// Incorrect: error G0739 : Unknown keyword argument 'nrows (did you mean ncols?)'
x = simulate(nrows=10);
nrows is an input to simulate(), but it is not a named keyword input, because the procedure did not declare a default value. Therefore, it cannot be called by name.
Will Keyword Inputs Slow Down My Code?
No. GAUSS resolves keyword inputs when your code is compiled, not when it runs. The compiler matches each name to its position, fills in the defaults for anything you left out, and rewrites the call as an ordinary positional call. By the time your program executes, the two versions are the same code.
That matters if you are calling a procedure thousands of times inside an estimation loop, so here is a test with ten million calls of each form:
proc (1) = addup(a, b=1, c=2, d=3);
retp(a + b + c + d);
endp;
n = 10000000;
t0 = hsec;
for i (1, n, 1);
x = addup(1, 2, 3, 4);
endfor;
print "positional:" (hsec-t0)/100 "sec";
t0 = hsec;
for i (1, n, 1);
x = addup(1, b=2, c=3, d=4);
endfor;
print "keyword: " (hsec-t0)/100 "sec";
positional: 0.73844300 sec keyword: 0.73672700 sec
Your timings will differ from machine to machine, but the two forms will always track each other. Write your calls whichever way reads best.
Conclusion
Keyword inputs are a small addition to the language that makes a large difference in how your code reads. To recap:
- Give an input a default value in the procedure definition to make it a keyword input.
- Call it by name, in any order, and leave out anything you want to keep at its default.
- Inputs without a default stay positional, and they come first.
- Defaults must be literals — scalars, matrices, strings, string arrays, or an empty matrix.
- Naming your inputs costs nothing at runtime.
The best part is that there is nothing to migrate. Every procedure you have already written keeps working exactly as it does today, and you can add defaults to them whenever it's convenient. The libraries that ship with GAUSS will adopt the same style in GAUSS 27, so your calls to them will get shorter too.
Keyword inputs are one of several GAUSS 26.1 features aimed at cleaner, more concise code. We'll cover the others in upcoming posts:
- Struct type inference — call a procedure that returns a struct without declaring the receiving variable first.
- Matrix and string array literals — use
{1, 2, 3}and{"a", "b"}directly in expressions and procedure calls.
