For Gauche 0.9.5


Next: , Previous: , Up: Core syntax   [Contents][Index]

4.12 Feature conditional

The cond-expand macro

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 #ifdef. In Common Lisp, you use reader macro #+ and #-. In Scheme, you have cond-expand:

Macro: cond-expand (feature-requirement command-or-definition …) …

[SRFI-0][R7RS] 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 else clause, 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.

The form (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 gauche.net.

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 cond-expand is 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 cond.

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.

Gauche-specific feature identifiers

gauche
gauche-X.X.X

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 (e.g. 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.)

gauche.os.windows
gauche.os.cygwin

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.)

gauche.ces.utf8
gauche.ces.eucjp
gauche.ces.sjis
gauche.ces.none

Either one of these is defined based on Gauche’s native character encoding scheme. See Multibyte strings, for the details.

gauche.net.tls

Defined if the runtime supports TLS in networking.

gauche.net.ipv6

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.

gauche.sys.threads
gauche.sys.pthreads
gauhce.sys.wthreads

If the runtime supports multithreading, gauche.sys.threads is defined (see Threads). Multithreading is based on either POSIX pthreads or Windows threads. The former defines gauche.sys.pthreads, and the latter defines gauche.sys.wthreads.

gauche.sys.sigwait
gauche.sys.setenv
gauche.sys.unsetenv
gauche.sys.clearenv
gauche.sys.getloadavg
gauche.sys.getrlimit
gauche.sys.lchown
gauche.sys.getpgid
gauche.sys.nanosleep
gauhce.sys.crypt
gauche.sys.symlink
gauche.sys.readlink
gauche.sys.select
gauche.sys.fcntl
gauche.sys.syslog
gauche.sys.setlogmask
gauche.sys.openpty
gauche.sys.forkpty

Those are defined based on the availability of these system features of the platform.

R7RS feature identifiers

r7rs

Indicates the implementation complies r7rs.

exact-closed

Exact arithmetic operations are closed; that is, dividing an exact number by a non-zero exact number always yields an exact number.

ieee-float

Using IEEE floating-point number internally. Full unicode support.

ratios

Rational number support

posix
windows

Either one is defined, according to the platform.

big-endian
little-endian

Either one is defined, according to the platform.


Next: , Previous: , Up: Core syntax   [Contents][Index]