From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Mark H Weaver Newsgroups: gmane.lisp.guile.bugs Subject: Re: multiple values bug in head / call-with-input-file Date: Mon, 02 May 2011 13:46:45 -0400 Message-ID: <87hb9dt2pm.fsf@netris.org> References: <223EB050-FA80-4887-B543-3B2EE0C8C6E1@bluewin.ch> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: dough.gmane.org 1304358440 24819 80.91.229.12 (2 May 2011 17:47:20 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Mon, 2 May 2011 17:47:20 +0000 (UTC) Cc: bug-guile@gnu.org To: Daniel Llorens Original-X-From: bug-guile-bounces+guile-bugs=m.gmane.org@gnu.org Mon May 02 19:47:16 2011 Return-path: Envelope-to: guile-bugs@m.gmane.org Original-Received: from lists.gnu.org ([140.186.70.17]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1QGxDH-0004vI-DC for guile-bugs@m.gmane.org; Mon, 02 May 2011 19:47:15 +0200 Original-Received: from localhost ([::1]:33909 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QGxDH-0008VX-07 for guile-bugs@m.gmane.org; Mon, 02 May 2011 13:47:15 -0400 Original-Received: from eggs.gnu.org ([140.186.70.92]:36644) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QGxDD-0008VH-ET for bug-guile@gnu.org; Mon, 02 May 2011 13:47:12 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QGxDC-0003Qr-Bn for bug-guile@gnu.org; Mon, 02 May 2011 13:47:11 -0400 Original-Received: from world.peace.net ([96.39.62.75]:47687) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QGxDC-0003Qn-6H for bug-guile@gnu.org; Mon, 02 May 2011 13:47:10 -0400 Original-Received: from 209-6-39-128.c3-0.smr-ubr1.sbo-smr.ma.cable.rcn.com ([209.6.39.128] helo=freedomincluded) by world.peace.net with esmtpa (Exim 4.69) (envelope-from ) id 1QGxD6-0004C1-Au; Mon, 02 May 2011 13:47:04 -0400 Original-Received: from mhw by freedomincluded with local (Exim 4.69) (envelope-from ) id 1QGxCp-0001kz-Le; Mon, 02 May 2011 13:46:47 -0400 In-Reply-To: <223EB050-FA80-4887-B543-3B2EE0C8C6E1@bluewin.ch> (Daniel Llorens's message of "Mon, 2 May 2011 15:23:32 +0200") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.3 (gnu/linux) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 96.39.62.75 X-BeenThere: bug-guile@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Bug reports for GUILE, GNU's Ubiquitous Extension Language" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-guile-bounces+guile-bugs=m.gmane.org@gnu.org Original-Sender: bug-guile-bounces+guile-bugs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.bugs:5547 Archived-At: Daniel Llorens writes: > scheme@(guile-user)> (call-with-input-string "hello" (lambda (p) (values 1 2))) > $1 = 1 > $2 = 2 > > but: > > scheme@(guile-user)> (call-with-input-file "hello" (lambda (p) (values 1 2))) > $1 = 1 Indeed this is suboptimal, and probably a bug. Thanks for reporting this! However, your fix is incorrect. By using dynamic-wind, your patch significantly changes the semantics of call-with-{input,output}-file. The docs state: If the procedure does not return, then the port will not be closed automatically unless it is possible to prove that the port will never again be used for a read or write operation. By using dynamic-wind, you have changed this. Now, if a continuation is invoked that causes control to leave the dynamic extent of call-with-{input,output}-file, the file will be closed. This is different from what the docs claim. Furthermore, if control re-enters that dynamic extent, the file will be _re-opened_ with a _fresh_ port. This causes several problems. First, the code within proc is probably not expecting that, and will continue to have copies of the old port around. To make matters worse: call-with-input-file will start reading from the beginning of the file again, and call-with-output-file will _truncate_ the file and resume writing from the beginning. I believe the proper fix is something like this: (define (call-with-input-file str proc) (let ((file (open-input-file str))) (call-with-values (lambda () (proc file)) (lambda vals (close-input-port file) (apply values vals))))) Would you like to prepare a new patch? Best, Mark > From 06f8aea901cd3da68a409a9932757209d91efc40 Mon Sep 17 00:00:00 2001 > From: Daniel Llorens > Date: Mon, 2 May 2011 14:54:20 +0200 > Subject: [PATCH] Fix call-with-input-file, call-with-output-file with multiple values > > * module/ice-9/r4rs.scm: Write call-with-input-file, call-with-input-file in terms of dynamic-wind. > --- > module/ice-9/r4rs.scm | 18 ++++++++++-------- > 1 files changed, 10 insertions(+), 8 deletions(-) > > diff --git a/module/ice-9/r4rs.scm b/module/ice-9/r4rs.scm > index 4d3feba..337e196 100644 > --- a/module/ice-9/r4rs.scm > +++ b/module/ice-9/r4rs.scm > @@ -144,10 +144,11 @@ automatically and the value yielded by the procedure is returned. > If the procedure does not return, then the port will not be closed > automatically unless it is possible to prove that the port will > never again be used for a read or write operation." > - (let* ((file (open-input-file str)) > - (ans (proc file))) > - (close-input-port file) > - ans)) > + (let ((port #f)) > + (dynamic-wind > + (lambda () (set! port (open-input-file str))) > + (lambda () (proc port)) > + (lambda () (if port (close-input-port port)))))) > > (define (call-with-output-file str proc) > "PROC should be a procedure of one argument, and STR should be a > @@ -160,10 +161,11 @@ automatically and the value yielded by the procedure is returned. > If the procedure does not return, then the port will not be closed > automatically unless it is possible to prove that the port will > never again be used for a read or write operation." > - (let* ((file (open-output-file str)) > - (ans (proc file))) > - (close-output-port file) > - ans)) > + (let ((port #f)) > + (dynamic-wind > + (lambda () (set! port (open-output-file str))) > + (lambda () (proc port)) > + (lambda () (if port (close-output-port port)))))) > > (define (with-input-from-port port thunk) > (let* ((swaports (lambda () (set! port (set-current-input-port port)))))