Sometimes you need to have a different piece of code depending on available features provided by the implemantation and/or platform. For example, you may want to switch behavior depending on whether networking is available, or to embed an implementation specific procedures in otherwise-portable code.
In C, you use preprocessor directives such as
In Common Lisp, you use reader macro
In Scheme, you have
[R7RS base] This macro expands to command-or-definition … if feature-requirement is supported by the current platform.
feature-requirement must be in the following syntax:
feature-requirement : feature-identifier | (and feature-requirement …) | (or feature-requirement …) | (not feature-requirement) | (library library-name)
The macro tests each feature-requirement in order, and if one is satisfied, the macro itself expands to the corresponding command-or-definition ….
The last clause may have
else in the position of
feature-requirement, to make the clause expanded
if none of the previous feature requirement is fulfilled.
If there’s neither a satisfying clause nor
cond-expand form throws an error. It is to detect the case early
that the platform doesn’t have required features. If the feature
you’re testing is optional, that is, your program works without the
feature as well, add empty
else clause as follows.
(cond-expand [feature expr] ; some optional feature [else])
feature-identifier is a symbol that indicates a feature. If such a feature is supported in the current platform, it satisfies the feature-requirement. You can do boolean combination of feature-requirements to compose more complex conditions.
(library library-name) is added in R7RS,
and it is fulfilled when the named library is available. Since
this is R7RS construct, you have to use R7RS-style library name—
list of symbols/integers, e.g.
(gauche net) instead of
Here’s a typical example: Suppose you want to have implementation-specific part for Gauche, Chicken Scheme and ChibiScheme. Most modern Scheme impelementations defines a feature-identifier to identify itself. You can write the conditional part as follows:
(cond-expand [gauche (gauche-specific-code)] [(or chicken chibi) (chicken-chibi-specific-code)] [else (fallback-code)] )
It is important that the conditions of
purely examined at the macro-expansion time, and
unfulfilled clauses are discarded.
Thus, for example, you can include macro calls or language extensions
that may not be recognized on some implementations. You can also
conditionally define global bindings.
Compare that to
cond, which examines conditions at runtime.
If you include unsupported macro call in one of the conditions, it
may raise an error at macro expansion time, even if that clause
will never be executed on the platform. Also, it is not possible
to conditionally define global bindings using
There’s a caveat, though. Suppose you want to save the result of macro expansion, and run the expanded result later on other platforms. The result code is based on the features of the platform the macro expansion takes place, which may not agree with the features of the platform the code will run. (This issue always arises in cross-compiling situation in general.)
See below for the list of feature identifiers defined in Gauche.
Indicates you’re running on Gauche. It is useful to put Gauche-specific
code in a portable program.
X.X.X is the gauche’s version
gauche-0.9.4), in case you want to have code
for specific Gauche version. (Such feature identifier is suggested by
R7RS; but it might not be useful if we don’t have means to compare versions.
Something to consider in future versions.)
Defined on Windows-native platform and Cygwin/Windows platform, respectively. If neither is defined you can assume it’s a unix variant. (Cygwin is supposedly unix variant, but corners are different enough to deserve it’s own feature identifier.)
Either one of these is defined based on Gauche’s native character encoding scheme. See Multibyte strings, for the details.
Defined if the runtime supports TLS in networking.
The two sub feature identifiers,
gauche.net.tls.mbedtls, are defined if each subsystem
mbedTLS is supported, respectively.
Defined if the runtime supports IPv6. Note that this only indicates Gauche has been built with IPv6 support; the OS may not allow IPv6 features, in that case you’ll get system error when you try to use IPv6.
If the runtime supports multithreading,
defined (see Threads). Multithreading is based on either POSIX pthreads
or Windows threads. The former defines
and the latter defines
Those are defined based on the availability of these system features of the platform.
Indicates the implementation complies r7rs.
Exact arithmetic operations are closed; that is, dividing an exact number by a non-zero exact number always yields an exact number.
Using IEEE floating-point number internally. Full unicode support.
Rational number support
Either one is defined, according to the platform.
Either one is defined, according to the platform.