[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
A few random I/O proposals
Well let me add my two cents worth to the debate. It seems that everyone
agrees that something must be done to handle I/O errors. Three proposals
for this:
1) Special return value: return #f on any error
2) Failure continuation: pass an extra argument to be called on error
3) Error system: on error, call implicit error handler
I think that it is best to look at the more general problem of
handling arbitrary errors, not just I/O. Sooner or later we will have
to do so and it would be ashame if there was a different error
handling mechanism just for I/O. For this reason I'm in favor of 3.
However, it does not mean that at this point we have to define all the
details of the error system. As a first pass, only I/O related error
situations could be defined. To keep it simple, error conditions could
be represented as symbols (e.g. FILE-NOT-FOUND) and later a new
datatype could be added if symbols are not sufficient.
A versatile error system can be added to Scheme with minimal extra machinery.
All that is needed is
1) a dynamic binding mechanism (there is a proposal for this already)
2) a name for the dynamic variable denoting the error handler procedure
(let's say we use ERROR-HANDLER)
3) a convention for passing information from the error point to the error
handler. I suggest that the error handler accepts a single argument
which is the error descriptor (a symbol for now).
A sample use of this system is:
(define (read-foo)
(call-with-current-continuation
(lambda (exit)
(dyn-let ((error-handler
(lambda (err-descr)
(case err-descr
((FILE-NOT-FOUND) (exit "file \"foo\" does not exist"))
((READ-ERROR) (exit "file \"foo\" can not be read"))
(else (exit "I/O error"))))))
(let ((port (open-input-file "foo")))
(let ((content (read port)))
(close-input-port port)
content))))))
For those who like the #f solution, you can always write:
(define old-open-input-file open-input-file)
(define (open-input-file filename)
(call-with-current-continuation
(lambda (exit)
(dyn-let ((error-handler (lambda (err-descr) (exit #f))))
(old-open-input-file filename)))))
While I'm at it, dynamic binding can also be used to remove the
procedures CURRENT-INPUT-PORT, CURRENT-OUTPUT-PORT,
WITH-INPUT-FROM-FILE and WITH-OUTPUT-TO-FILE because they can be written as:
(define (CURRENT-INPUT-PORT) (dyn-ref CURRENT-INPUT-PORT))
(define (WITH-INPUT-FROM-FILE filename thunk)
(dyn-let ((CURRENT-INPUT-PORT (open-input-file filename)))
(let ((result (thunk)))
(close-input-port (CURRENT-INPUT-PORT))
result)))
Marc