version-case.txt

version-case: conditionally compile code based on current version number

This library provides support for conditionally compiling code based
on the version of PLT Scheme.  One common application of this module
is to write compatibility bindings.

1. Example

The following example shows how one can write unit code that works
with both the old and new unit libraries.

  (module some-sample-unit-code mzscheme
    (require (planet "version-case.ss" ("dyoo" "version-case.plt" 1))
             (lib "mred.ss" "mred"))
  
  
  
  
    (version-case
     [(version<= (version) "360")
      (printf "old unit code~n")
      (require (lib "tool.ss" "drscheme")
               (lib "unitsig.ss"))
  
      (define tool@
        (unit/sig drscheme:tool-exports^
          (import drscheme:tool^)
          (define (phase1)
            (message-box "phase1"))
          (define (phase2)
            (message-box "phase2"))))]
  
     [else
      (printf "new unit code~n")
      (require (lib "tool.ss" "drscheme")
               (lib "unit.ss"))
      (define-unit tool@
        (import drscheme:tool^)
        (export drscheme:tool-exports^)
        (define (phase1)
          (message-box "phase1"))
        (define (phase2)
          (message-box "phase2")))]))

Another simple example:

  (module another-example scheme/base
    (require (planet dyoo/version-case)
             (for-syntax scheme/base))
    (printf "~a~n" (version-case [(version<= (version) "4")
                                  'huh?]
                                 [else
                                  'ok])))

2. Usage

  (version-case [test code ...]
                ...
                [else code ...])

version-case is a macro that expands out to one of the
code blocks, depending on which test succeeds first.  The
test expression is evaluated at compile-time.  Some
version-comparing functions are available for convenience.

(version< v1 v2) -> boolean?
  v1 : string?
  v2 : string?

Returns true if v1 is less than v2.

(version<= v1 v2) -> boolean?
  v1 : string?
  v2 : string?

Returns true if v1 is less than or equal to v2.

(version= v1 v2) -> boolean?
  v1 : string?
  v2 : string?

Returns true if v1 is equal to v2.

(version> v1 v2) -> boolean?
  v1 : string?
  v2 : string?

Returns true if v1 is greater than v2.

(version>= v1 v2) -> boolean?
  v1 : string?
  v2 : string?

Returns true if v1 is greater than or equal to v2.

3. Gotchas

The tests are done at compile time.  If the language of your module
doesn’t include compile-time bindings for function application, you
may see funny error messages.  For example, scheme/base
doesn’t automatically provide the necessary compile-time bindings, so
if you use version-case with it, you also need to do a
(require (for-syntax scheme/base)).

4. Thanks

Special thanks to Carl Eastlund providing the implementation that
doesn’t use eval, and for feedback.