config Declarations: command-line overrides¶
The four main declaration keywords that have been introduced so far —
var
, const
, param
, and type
— support a mode in which
their initializing expressions in the source code can be overridden on
the command-line. This is achieved by prefixing the declaration with
the keyword config
. Chapel's config
feature provides a simple
means of specifying and overriding default values.
config var
and config const
¶
Configuration variables are variables whose default values can be overridden on the executable's command-line. Here's a simple example:
config var n = 10;
Like a traditional var
declaration, this creates a variable named
n of type int
, initialized to the value 10. However, the
config
prefix causes the compiler to add a command-line flag to
the generated executable that supports overriding that default value.
For example, if we run the program as follows:
./a.out --n 1000
then n will be initialized to the value 1000 for that execution of
the program. The arguments for these flags can also be specified
using =
(with no spaces) as the separator between the argument
name and its value, as follows:
./a.out --n=1000
There is no difference between these two forms—it's simply a matter of taste.
As with normal variables, a config var
can be re-assigned
throughout its lifetime. In contrast, config const
declarations
cannot be changed once they are initialized, whether that initial
value comes from the source code or the command-line. The following
statement declares a pair of configurable constants:
config const epsilon = 0.01,
debug = false;
As with the previous case, we can override their default values on the
executable's command-line. For instance the following switches to a
smaller value of epsilon and flips debug to true
:
./a.out --epsilon=0.000001 --debug=true
Boolean config
declarations, like debug above, also support a
mode in which they can be set to true
simply by using the flag
without a supporting value. Thus, the previous command-line could
also have been written:
./a.out --epsilon=0.000001 --debug
config param
and config type
¶
Chapel also supports configurable param
and type
declarations
via command-line flags. However, since param
values and types
must be known to the compiler, the default values are overridden using
flags on the compiler rather than the generated executable.
As an example, the following statements declare a series of
configurable param
and type
symbols:
config param verbose = false,
bitMask = 1 << 8,
size = numBits(int);
config type age = uint(8);
When overriding config
declarations in the compiler the -s
flag is used to set the new value. As an example, to set verbose
to true
, we could compile as follows:
chpl -sverbose=true configs2.chpl
or:
chpl -s verbose=true configs2.chpl
As with the generated executable, boolean values can also be set on the compiler's command line simply using the name of the flag. Thus, the following would be equivalent to the previous line:
chpl -sverbose configs2.chpl
As you'd expect, multiple config
declarations can be overridden at
once. For example, this command-line overrides the default
initializers for bitMask, size, and age:
chpl -sbitMask=0b00001111 -ssize=16 -sage='uint(16)' configs2.chpl
One of the nice things about setting config
declarations on the
compiler's command-line is that the specified value can be an
arbitrary Chapel expression, provided that the compiler can evaluate
it in place of the source-based initialization expression. Thus, we
can use more interesting expressions when setting compile-time
config
values. For example, the following compiler lines specify
bitMask, size, and age using expressions other than simple
literals and type names:
chpl -sbitMask='1 << 10' -ssize='numBits(bitMask.type)/2' configs2.chpl
chpl -sage='if verbose then uint(32) else uint(16)' configs2.chpl
Note the use of quotes in some of the examples above. These are not required by Chapel itself, but are used to pass nontrivial expressions through the command-line shell (e.g., bash) such that they reach Chapel as a single uninterpreted argument. For example, parenthesis have special meaning for many command-shells, so the use of quotes above tells the shell to ignore them. Other cases use quotes to pass expressions containing whitespace to the Chapel compiler as a single argument. Details about which characters have special meaning and how they can be preserved depend on the specific shell being used and are beyond the scope of this article.
Setting config
defaults on the compiler's command-line also
supports more radical alterations to the code. For example, we
could change age from an integral type to a floating point type:
--n=1000 --epsilon=0.000000001
Note that config
declarations are processed in the order specified
by the source code and compiler, not the order that they occur on the
command-line. Moreover, the initializing expressions must make sense
when considered in the source code context. Thus, the command-line
override for a given config
can refer to other declarations that
precede it in a given module. For instance, we can set age in terms
of the config param
size since it appeared earlier in the code:
chpl -sage='int(size)'
However, the reverse would not be possible since age has not been initialized when size is declared.
Similarly, subsequent declarations in the source code can themselves
be based on config
declarations. For instance, here are some
declarations that are based on the config param
and config
type
statements shown above and could follow them:
type myInt = int(size);
param sizeOfAge = numBits(age);
Compile time overrides for config var
and config const
¶
Users can also specify default expressions for config var
and
config const
declarations on the compiler's command-line. As with
other compile-time overrides, complex or symbolic expressions can be
used since the compiler is involved. As an example, let's look at
a variation on one of our earlier declarations:
config const n = 10,
epsilon = 0.01;
The following compiler command can be used to override the source code initializer for epsilon so that it will be a function of n by default:
-sepsilon=1.0/n
Such an initializer could not be specified on the executable
command-line since the compiler is out of the picture by then. At
that point, the values for a config var
or config const
are
restricted to the set of strings that can legally be cast to that
type.
Having compiled epsilon to be set in this way, if we specify a value for n on the executable's command line:
--n=1000
then epsilon will be computed in terms of it, resulting in the value:
0.001
Note that the compiler's command-line override can still be re-overridden on the executable's command-line as usual:
--n=1000 --epsilon=0.000000001
Scope of config
declarations¶
Because all config
declarations are processed at program startup
time, they must appear at module scope. We haven't talked about
modules yet, so for now, think of them as needing to appear as
top-level statements in a file.