Re: On fileevent...

From: Erik Ostrom <>
Date: Wed, 15 Nov 1995 14:10:08 -0500

> - let's suppose to have an event (a lambda) registered to an opened file. The
> fileevent will continue to call the lambda even if the eof was reached.
> I know I can check the eof in the lambda, but how much time the function
> takes?

Testing for eof shouldn't significantly slow you down (provided you delete
the fileevent handler once you get eof, so it doesn't keep on uselessly
calling your lambda forever). It's just a few added statements every time
you go through a loop.

I don't know how you would do it if you're reading with read-line or
read, but if you're using read-char, the following code would be
reasonable in a callback:

  (let loop ((c (read-char f)))
    (if (eof-object? c)
          ;;; ... code to do any necessary cleanup goes here ...
          ;;; ... and then:
          (fileevent f 'readable ""))
          ;;; ... code to do the real work goes here ...
          ;;; ... and then:
          (if (char-ready? f)
              (loop (read-char f))))))

The extra eof-object? each time through the loop is pretty insignificant;
the cleanup section lets you do things like remove windows related to
file reading (e.g., a "stop" button); and the call to fileevent ensures
that the callback won't be called any more times than needed.

If you're doing character-by-character input, you _can_ get a significant
speed increase by coding in C a function that simply returns _all_ the
characters waiting to be read on a given input port. Just moving the read
loop into C sped my program up quite a bit, and it could be rewritten for
still more efficiency by peeking at buffer structures and such. My
read-ready function is in
somewhere. (The main point of the callbacks package was to provide
exactly what fileevent does for input ports.)

> - let's suppose the lambda is a general purpose function that does not know
> which is the calling file trigger. It could be a great improvement to
> provide the lambda the fileid (using a lambda parameter). I know this is
> not compatible with the Tk, but...

This is simple enough to accomplish without changing fileevent:

(define (general-purpose-callback f)
  ;;; read from f and do appropriate things

(define (attach-general-purpose-callback-to f)
  (fileevent f 'readable (lambda () (general-purpose-callback f))))

... i.e., for the fileevent script, just use a closure that captures
the appropriate input port in its environment, and then calls your
general-purpose function with that argument. This keeps the Tk
compatibility, and I think feels more scheme-like than having fileevent
call back with an argument. If you want, though, you can redefine
fileevent to accomplish what you want:

(define fileevent
  (let ((old-fileevent fileevent))
    (lambda (file mode . script)
      (if (and (pair? script) (procedure? (car script)))
        (old-fileevent file mode (lambda () ((car script) file)))
        (apply old-fileevent file mode script)))))

This will work just like fileevent, but you give it callbacks that
take a file as argument: (fileevent f 'readable general-purpose-callback).

All the code in this message is untested, but it should work with minimal
tweaking. Apologies if these responses aren't helpful.
Received on Wed Nov 15 1995 - 20:22:57 CET

This archive was generated by hypermail 2.3.0 : Mon Jul 21 2014 - 19:38:59 CEST