ttsiodras
ttsiodras

Reputation: 11258

OCaml Printf.printf - missing output mystery

The following code...

type 'a osResult =
  Success of 'a
| Error of string


let errorCatcher f =
  try
    let result = f () in
    Success result
  with Unix.Unix_error (code, fun_name, arg) ->
    Error(String.concat ":" [(Unix.error_message code); fun_name; arg])

let my_getcwd () = 
  errorCatcher (fun () -> Unix.getcwd ())

let _ =
  print_endline "The Start";
  let result = my_getcwd () |> function
  | Success folder -> Printf.sprintf "getcwd:\n\t%s\n" folder
  | Error errMessage -> Printf.sprintf "getcwd (error):\n\t%s\n" errMessage
  in
  print_string result ;
  print_endline "The End."
;;

...compiles fine:

$ corebuild -tag debug test1.native

...and runs fine:

$ ./test1.native 
The Start
getcwd:
        /home/ttsiod/work/byePythonHelloOCaml
The End.

But if I change the main body to this:

let _ =
  print_endline "The Start";
  my_getcwd () |> function
  | Success folder -> Printf.printf "getcwd:\n\t%s\n" folder
  | Error errMessage -> Printf.printf "getcwd (error):\n\t%s\n" errMessage
  ;
  print_endline "The End."
;;

... then apparently the last print statement ("The End") gets lost or something...

$ ./test2.native 
The Start
getcwd:
        /home/ttsiod/work/byePythonHelloOCaml

Initially, I thought this is a case of stdout buffering not being flushed.

But the docs of print_endline clearly claim that it flushes stdout, so I am at a loss - and adding "flush" didn't help, either:

let _ =
  print_endline "The Start";
  my_getcwd () |> function
  | Success folder -> Printf.printf "getcwd:\n\t%s\n" folder
  | Error errMessage -> Printf.printf "getcwd (error):\n\t%s\n" errMessage
  ;
  print_endline "The End." ;
  flush stdout
;;

Help?

Upvotes: 1

Views: 2597

Answers (1)

Thomas Leonard
Thomas Leonard

Reputation: 7196

The print_endline is treated as part of the Error case. From the indentation, this is clearly not what you meant, but unfortunately the OCaml compiler doesn't warn about this.

You can use begin and end (or just parentheses) to make it work:

let () =
  print_endline "The Start";
  my_getcwd () |> begin function
  | Success folder -> Printf.printf "getcwd:\n\t%s\n" folder
  | Error errMessage -> Printf.printf "getcwd (error):\n\t%s\n" errMessage
  end;
  print_endline "The End." ;
  flush stdout

Alternatively, without using ;,

let () =
  let () = print_endline "The Start" in
  let () = match my_getcwd () with
    | Success folder -> Printf.printf "getcwd:\n\t%s\n" folder
    | Error errMessage -> Printf.printf "getcwd (error):\n\t%s\n" errMessage
  in
  let () = print_endline "The End." in
  flush stdout

Upvotes: 3

Related Questions