Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!sdd.hp.com!spool.mu.edu!munnari.oz.au!goanna!ok From: ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) Newsgroups: comp.lang.scheme Subject: Re: open-input-file [topics from hell, part 2] Message-ID: <5387@goanna.cs.rmit.oz.au> Date: 24 Apr 91 08:04:25 GMT Article-I.D.: goanna.5387 References: <9104211907.AA25632@august> Organization: Comp Sci, RMIT, Melbourne, Australia Lines: 69 I note that Common Lisp has (CLtL 2nd ed, p646) (open filename &key :direction :element-type :external-format :if-exists :if-does-not-exist) :direction can be :input like (open-input-file filename) :output like (open-output-file filename) :io -- no equivalent :probe like (file-exists? filename) :if-exists is used for :direction :output or :io and can be :error signal error if the file exists :new-version make a new version :rename rename old file out of the way :rename-and-delete :overwrite write on top of the old file :append *NOT* the same as C's "append" mode :supersede more or less the same as C's "write" mode. nil return nil to indicate failure :if-does-not-exist is used for all directions and can be :error signal an error if the file does not exist :create make an empty file and keep going nil return nil to indicate failure. I note that (open filename :direction :input :if-does-not-exist :create) is a combination which no-one has suggested yet. I further note that Common Lisp does _not_ provide any way of saying "if the file _does_ exist but you aren't allowed to write on it or rename it or delete it, do such-and-such". The basic choice in each case is (return false, signal an error, handle the situation and continue) It seems to me that the simplest and most "Scheme-like" approach is to add an optional argument, whose value would be a function: (open-input-file filename [handler]) (open-output-file filename [handler]) where the handler is a function of 2 arguments: -- a system-dependent code indicating the nature of the problem -- the filename after (system-dependent) expansion and if the handler returns normally its value would become the value of the call to open-input-stream. The handler not being supplied, the default would be to signal an error. Someone who -wants- #f to be returned has only to do (open-input-file filename (lambda (e n) #f)) There is something going on here which means that always signalling an error and relying on an error handling system might not be the best idea, and that is that this approach makes retrying easy. (open-input-file filename (lambda (error-code truename) (format #t "~&Can't read ~A~%~ System error code ~A~%~ Please enter another name: " truename error-code) (open-input-file (read-string)))) The only Scheme implementation I actually understand is Elk, and it would be very easy to add this to Elk. I note that C's approach to error reporting (namely leaving an error code lying around in a global variable) is extremely invonvenient: there is *no* way that you can *trust* the value of that global variable. This approach (the handler function receiving the error code) provides a clean way of picking up the error code without relying on global variables, and makes sense even if you are using engines and the like. -- Bad things happen periodically, and they're going to happen to somebody. Why not you? -- John Allen Paulos.