caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Re: [Caml-list] closing file descriptors and channels
  2003-11-20 16:55 [Caml-list] closing file descriptors and channels Christian Schaller
@ 2003-11-20 16:54 ` Tim Freeman
  2003-11-21 16:28   ` skaller
  0 siblings, 1 reply; 7+ messages in thread
From: Tim Freeman @ 2003-11-20 16:54 UTC (permalink / raw)
  To: Christian.Schaller; +Cc: caml-list

From: "Christian Schaller" <Christian.Schaller@siemens.com>
>Yup, I've seen this one already.  This one makes it complicated, since
>for propagating the exception, I have to duplicate the closings:
>
>    .
>    .
>    .
>  with          
>  End_of_file -> output_string oc (line ^ "\n");
>  Found line -> (close_out oc; close_in ic; raise Found line);
>  close_out oc;
>  close_in ic

Java's "try ... finally" is useful and can be recreated in ML.  Here's
a definition:

let finally (body: unit -> 'a) (handler: unit -> unit): 'a =
  let result: 'a option ref = ref None
  in begin
      begin
        try begin
          result := Some (body ());
        end with e -> begin
          handler ();
          raise e;
        end;
      end;
      handler ();
      match !result with
          Some r -> r
        | _ -> failwith "Confused in finally";
    end;;

and here's how to use it for your example:

   let ic = "open the input file somehow" in
   finally (fun () ->
      let oc = "open the output file somehow" in
      finally (fun () ->
         .
	 .  (sometimes raise Found somewhere in here)
	 .
	 with 
	 End_of_file -> output_string oc "whatever")
      (fun () -> close_out oc))
   (fun () -> close_in ic)

I have to admit Java's syntax for try...finally is better.
-- 
Tim Freeman                                                  tim@fungible.com
GPG public key fingerprint ECDF 46F8 3B80 BB9E 575D  7180 76DF FE00 34B1 5C78 
Your levity is good.  It relieves tension and fear of death.  -- Terminator 3

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: [Caml-list] closing file descriptors and channels
@ 2003-11-20 16:55 Christian Schaller
  2003-11-20 16:54 ` Tim Freeman
  0 siblings, 1 reply; 7+ messages in thread
From: Christian Schaller @ 2003-11-20 16:55 UTC (permalink / raw)
  To: Xavier Leroy; +Cc: caml-list

> close_out and close_in both perform the equivalent of a Unix.close on
> the underlying Unix file descriptor, and, yes, closing something that
> is already closed is an I/O exception.  So, one possibility is to
> close only one of the three entities file_descr, oc and ic.  It's best
> to close the output channel oc, since this will flush its buffer.

What I did was just skipping the Unix.close, but close *both* in- and
out-channels and it worked (until now ;-) ).

> Side remark: you'd need to close the file descriptor also in the case
> where the line is found and the exception Found is raised.

Yup, I've seen this one already.  This one makes it complicated, since
for propagating the exception, I have to duplicate the closings:

    .
    .
    .
  with          
  End_of_file -> output_string oc (line ^ "\n");
  Found line -> (close_out oc; close_in ic; raise Found line);
  close_out oc;
  close_in ic

Since I am new to streams & co, are there any kind of rules when to
prefer streams to normal I/O?  Is there more overhead when using
streams?  Shouldn't I use streams when working on a regular text file?

What if I want to break from a stream with an exception (as above the
Found exception)?  Closing/accessing the channel is only possible in the
stream creation as in my corrected version:

let read_lines ch =
  let read_new_line n =
    try Some (input_line ch)
    with End_of_file -> close_in ch; None in
  Stream.from read_new_line

Now I want to stop reading lines after a certain number of lines

let rec read_n_lines n =
  parser
  [< 'line; rest >] -> if n <> 0 then print_endline line; read_n_lines
(n-1) else ()
  [< >] -> ()

Didn't type-check it, though ;-)  Anyway, how can I close the stream in
this case?

Thanks!

- Chris

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] closing file descriptors and channels
  2003-11-20 16:54 ` Tim Freeman
@ 2003-11-21 16:28   ` skaller
  0 siblings, 0 replies; 7+ messages in thread
From: skaller @ 2003-11-21 16:28 UTC (permalink / raw)
  To: Tim Freeman; +Cc: Christian.Schaller, caml-list

On Fri, 2003-11-21 at 03:54, Tim Freeman wrote:
> From: "Christian Schaller" <Christian.Schaller@siemens.com>

> 
> I have to admit Java's syntax for try...finally is better.

.. but we have camlp4 .. :-)


-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] closing file descriptors and channels
  2003-11-20 16:35 ` Xavier Leroy
  2003-11-20 17:01   ` Tim Freeman
@ 2003-11-20 17:14   ` Nicolas George
  1 sibling, 0 replies; 7+ messages in thread
From: Nicolas George @ 2003-11-20 17:14 UTC (permalink / raw)
  To: Caml mailing list

[-- Attachment #1: Type: text/plain, Size: 596 bytes --]

Le decadi 30 brumaire, an CCXII, Xavier Leroy a écrit :
> The other possibility is to use close_out_noerr and close_in_noerr
> that will just ignore the errors arising from the closing of the
> underlying file descriptor.  But this can be dangerous:

This can be even more dangerous if another file has been opened between
the two closes (which can be invisible in threaded programs) and has got
the file descriptor that has just been closed.

I am preparing a RFC for this list about a complete rewrite of the I/O
subsystem, and this is definitively a problem that must be addressed.

[-- Attachment #2: Type: application/pgp-signature, Size: 185 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] closing file descriptors and channels
  2003-11-20 16:35 ` Xavier Leroy
@ 2003-11-20 17:01   ` Tim Freeman
  2003-11-20 17:14   ` Nicolas George
  1 sibling, 0 replies; 7+ messages in thread
From: Tim Freeman @ 2003-11-20 17:01 UTC (permalink / raw)
  To: xavier.leroy; +Cc: Christian.Schaller, caml-list

From: Xavier Leroy <xavier.leroy@inria.fr>
>The other possibility is to use close_out_noerr and close_in_noerr
>that will just ignore the errors arising from the closing of the
>underlying file descriptor.  But this can be dangerous: certain
>implementations of NFS can report write errors not at the time of the
>writing, but at the time of the closing, and presumably you're
>interested in getting these errors reported.

It's also dangerous if you have multiple threads because the scenario
I mentioned at http://caml.inria.fr/archives/200311/msg00254.html is
possible.
-- 
Tim Freeman                                                  tim@fungible.com
GPG public key fingerprint ECDF 46F8 3B80 BB9E 575D  7180 76DF FE00 34B1 5C78 
Your levity is good.  It relieves tension and fear of death.  -- Terminator 3

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Caml-list] closing file descriptors and channels
  2003-11-20 16:14 Christian Schaller
@ 2003-11-20 16:35 ` Xavier Leroy
  2003-11-20 17:01   ` Tim Freeman
  2003-11-20 17:14   ` Nicolas George
  0 siblings, 2 replies; 7+ messages in thread
From: Xavier Leroy @ 2003-11-20 16:35 UTC (permalink / raw)
  To: Christian Schaller; +Cc: caml-list

> Can anyone tell me how to close a file descriptor successfully?  In the
> code below
> 
> (* Append new line if condition cond is not satisfied on any line.
>    Otherwise, raise exception and return the line that fulfills the
> condition. *)
> let append_line_cond file_name line cond = 
>   let file_descr = Unix.openfile file_name [Unix.O_RDWR; Unix.O_APPEND]
> 0o644 in
>   let ic = Unix.in_channel_of_descr file_descr in
>   let oc = Unix.out_channel_of_descr file_descr in
>   try
>   (* Read line by line and check if condition is true.  If so, leave the
>      function and return the line that satisfied the condition *)
>   while true do 
>     let line = input_line ic in
>     if cond line
>     then raise (Found line)
>   done          
>   with          
>   End_of_file -> output_string oc (line ^ "\n");
>   (* close all channels *)
>   Unix.close file_descr;
>   close_out oc;
>   close_in ic
> 
> I get a Sys_error "Bad file descriptor".  As far as I figured out, the
> problem is related with the creation of the two channels for input and
> output.  If I comment out the Unix.close, everything works fine, but I
> don't know if the file_descr will be automatically closed.  Hm...

close_out and close_in both perform the equivalent of a Unix.close on
the underlying Unix file descriptor, and, yes, closing something that
is already closed is an I/O exception.  So, one possibility is to
close only one of the three entities file_descr, oc and ic.  It's best
to close the output channel oc, since this will flush its buffer.

The other possibility is to use close_out_noerr and close_in_noerr
that will just ignore the errors arising from the closing of the
underlying file descriptor.  But this can be dangerous: certain
implementations of NFS can report write errors not at the time of the
writing, but at the time of the closing, and presumably you're
interested in getting these errors reported.

Side remark: you'd need to close the file descriptor also in the case
where the line is found and the exception Found is raised.

> Yet another closing-channels-question.  If I use streams instead of
> reading a file line by line, where exactly do I have to close the
> channel?  Is close_in on the right position below?
> 
> let read_lines ch =
>   let read_new_line n =
>     try Some (input_line ch)
>     with End_of_file -> close_in ch in
>   Stream.from read_new_line

This looks fine, except that you need to return None in the
End_of_file case.  (The typechecker will remind you about this :-)

Hope this helps,

- Xavier Leroy

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [Caml-list] closing file descriptors and channels
@ 2003-11-20 16:14 Christian Schaller
  2003-11-20 16:35 ` Xavier Leroy
  0 siblings, 1 reply; 7+ messages in thread
From: Christian Schaller @ 2003-11-20 16:14 UTC (permalink / raw)
  To: caml-list

Hi,

Can anyone tell me how to close a file descriptor successfully?  In the
code below

(* Append new line if condition cond is not satisfied on any line.
   Otherwise, raise exception and return the line that fulfills the
condition. *)
let append_line_cond file_name line cond = 
  let file_descr = Unix.openfile file_name [Unix.O_RDWR; Unix.O_APPEND]
0o644 in
  let ic = Unix.in_channel_of_descr file_descr in
  let oc = Unix.out_channel_of_descr file_descr in
  try
  (* Read line by line and check if condition is true.  If so, leave the
     function and return the line that satisfied the condition *)
  while true do 
    let line = input_line ic in
    if cond line
    then raise (Found line)
  done          
  with          
  End_of_file -> output_string oc (line ^ "\n");
  (* close all channels *)
  Unix.close file_descr;
  close_out oc;
  close_in ic

I get a Sys_error "Bad file descriptor".  As far as I figured out, the
problem is related with the creation of the two channels for input and
output.  If I comment out the Unix.close, everything works fine, but I
don't know if the file_descr will be automatically closed.  Hm...

Yet another closing-channels-question.  If I use streams instead of
reading a file line by line, where exactly do I have to close the
channel?  Is close_in on the right position below?

let read_lines ch =
  let read_new_line n =
    try Some (input_line ch)
    with End_of_file -> close_in ch in
  Stream.from read_new_line

Thank you so much, but working with files in OCaml is kind of pain in
the butt :(

Cheers,
  Chris

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2003-11-21 17:29 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-11-20 16:55 [Caml-list] closing file descriptors and channels Christian Schaller
2003-11-20 16:54 ` Tim Freeman
2003-11-21 16:28   ` skaller
  -- strict thread matches above, loose matches on Subject: below --
2003-11-20 16:14 Christian Schaller
2003-11-20 16:35 ` Xavier Leroy
2003-11-20 17:01   ` Tim Freeman
2003-11-20 17:14   ` Nicolas George

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).