[racket] Adjusting behavior based on version of Racket?

From: Greg Hendershott (greghendershott at gmail.com)
Date: Mon Oct 7 13:58:03 EDT 2013

This is a general question with a specific motivating example.

For 5.3.6 and earlier I wrote this:

https://github.com/greghendershott/frog/blob/master/frog/watch-dir.rkt

;; This is a poor person's version of OS-specific mechanisms like
;; FindFirstFileChangeNotification on Windows and fsevents on OS X.
;; Instead this does a checksum of a path's contents, running a thread
;; to check periodically.

A thread periodically wakes up, looks for changes, then goes back to sleep.

Next, in the upcoming version of Racket there will be a `filesystem-change-evt`:

http://www.cs.utah.edu/plt/snapshots/current/doc/reference/Filesystem.html?q=change-evt#%28def._%28%28quote._%7E23%7E25kernel%29._filesystem-change-evt%29%29

To detect that _something_ changed, I could use this instead of a
sleeping thread. Should be more efficient. I would still need to
determine _what_ changed, so I'd keep using that part of the code. And
in theory `filesystem-change-evt` might be unsupported on a given OS,
in which case I should fall back to my status quo code, completely.

And also: If I want to remain compatible with 5.3.6 and earlier, I
can't statically require `filesystem-change-evt`. If 5.3.5 and
earlier, obviously another case to use the status quo code,
completely.

I haven't done this (a runtime check for a Racket-version-dependent
capability) before. What's the recommended way -- use
`dynamic-require`?

As in the following pseudo-code (which also is supposed to handle the
OS-doesn't-support case)?

(define (our-filesystem-change-evt path)
  ;; An equivalent using thread that sleeps. Works in 5.3.6 and earlier.
  ....)

(define filesystem-change-evt
  ;; 1. filesystem-change-evt doesn't exist i.e. 5.3.6 or earlier
  ;; 2. filesystem-change-evt exists but OS doesn't support it
  ;; 3. filesystem-change-evt exists and OS supports it
  (with-handlers ([exn:fail:contract? (const our-filesystem-change-evt)]) ;1
    (define f (dynamic-require 'racket/base 'filesystem-change-evt))
    (match (f (build-path 'same) (const our-filesystem-change-evt))
      [(? procedure? f) f] ;2
      [(? evt?) f]))) ;3

Posted on the users mailing list.