Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!usc!snorkelwacker.mit.edu!ai-lab!zurich.ai.mit.edu!markf From: markf@zurich.ai.mit.edu (Mark Friedman) Newsgroups: comp.lang.scheme Subject: Re: I/O is a special case (long). Message-ID: Date: 30 Apr 91 17:20:27 GMT References: <559sis-b@massey.ac.nz> Sender: news@ai.mit.edu Reply-To: markf@zurich.ai.mit.edu Organization: M.I.T. Artificial Intelligence Lab. Lines: 120 In-reply-to: E.Ireland@massey.ac.nz's message of 29 Apr 91 21:32:29 GMT In article <559sis-b@massey.ac.nz> E.Ireland@massey.ac.nz (Evan Ireland) writes: >It seems to me that the simplest and most "Scheme-like" approach is to add > (open-input-file filename [handler]) > (open-output-file filename [handler]) > -- 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)) I support this proposal. Let me summarise the good points as I see them. (1) No changes are required to existing code. (Chris Hanson points out that "a CL-like condition system can be added without changing any code, and is totally compatible with the standard.", but this approach is simpler). Passing error continuations and signalling errors is simpler than just signalling errors? (2) Novice users, and expert users who *want* their programs to terminate with error conditions for these cases, don't have to provide "success" continuations. (Of course a condition system would allow this too, if you simply fail to handle the condition). (3) The idea of optional failure continuations for input/output procedures is "easier to understand" than a condition system. We both agree that if you don't want to handle the error, both approaches are equivalent. So the question is whether (open-input-file file (lambda (e n) (my-handler e n))) is any simpler than (bind-handler file-open-error my-handler (lambda () (open-input-file file))) In this, the simplest case, I don't really think that there is any significant difference. In the most general case you have to have something like the following for the continuation approach: (define (my-procedure arg file-input-handler read-error-handler bad-input-handler) (read-and-process (open-input-file (get-file-name arg) file-input-handler) read-error-handler bad-input-handler)) with the list of handlers being passed around getting longer and longer as your programs get larger and larger. Dynamic error handlers neatly solve that problem. >I prefer the current situation of being able to say that a certain >procedure accepts arguments of a certain sort and signals an error if >the arguments are not valid. As Chris said, we can build a condition >system consistant with this. You are then free to handle the >conditions as you see fit (e.g. return some special error object). If you are programming in a mainly functional style, you will probably (1) Functions, such as sqrt, which are often partial. It is often tidier to check, before applying a function, whether the arguments you intend to pass are valid, and the tools for doing this are normal function applications e.g. (if (< x 0) (do-something-with-negative-number) (* 5 (sqrt x)) The question that we are trying to answer is what to do when you don't (or can't) check whether the arguments are valid. (2) Side-effecting procedures, mostly for I/O. Here the validity of an argument often depends on factors external to the program, e.g. the current state of the file system, which cannot be checked by the program, unless it resorts to other I/O procedures! For case (2), however, since we cannot check in this way, we need an --- Condition systems: would solve the problem, but are more cumbersome than simple failure continuations. I still don't see why they are more cumbersome (I argue that they are less cumbersome). Also the error handlers are further removed from potential-error-causing procedure calls, making things more difficult to follow. They are less difficult to follow than procedure calls with extraneous arguments. In the case where the handler is not bound immediately before a call to a procedure which might signal the condition corresponding to that handler, your approach would have to pass the handler along the call chain ala MY-PROCEDURE above. --- Failure continuations: could be added as optional parameters to I/O procedures. Easy to understand, use, and implement, and requiring minimal changes to the language. Well, I don't agree that they are easier to understand and use. Note that these are "plain" old continuations, not requiring call/cc. Actually, they look like "plain" old procedures to me. -Mark -- Mark Friedman MIT Artificial Intelligence Lab 545 Technology Sq. Cambridge, Ma. 02139 markf@zurich.ai.mit.edu